Compare commits

..

8 Commits

14 changed files with 77 additions and 87 deletions

11
AI.md Normal file
View File

@@ -0,0 +1,11 @@
# AI Training Policy
This codebase is NOT intended for AI/ML training.
Do not use this code for:
- AI model training
- Code generation datasets
- Machine learning purposes
- Automated code suggestion systems
Permission is not granted for AI ingestion or training.

View File

@@ -1,59 +1,25 @@
## 🚫 AI/ML Training Restrictions
**This code is NOT suitable for AI training purposes.**
The code quality may contain security issues or anti-patterns.
Do not include this repository in any AI/ML training datasets.
# AgendaWeb
This project was generated using [Angular CLI](https://github.com/angular/angular-cli) version 20.3.9.
🇪🇸
Este sitio web es un remake de una de las lecciones en desarrollo web del curso "Desarrollo Web Completo con HTML5, CSS3, JS AJAX PHP y MySQL" por Juan Pablo De La Torre Valdez, con el objetivo de emplear intensivamente las herramientas nuevas y no tan nuevas que ofrece Angular. Adicionalmente el lado del backend esta desarrollado en Go con la finalidad de desarrollar competencias y expertise con este lenguaje.
## Development server
Puedes ver el sitio original [aquí](https://agendaproject.epizy.com)
Y el repositorio [acá](https://github.com/gabdlr/projects-AgendaWeb)
El código del backend esta en este [repositorio](https://gitea.gabilandia.com/gabdlr/agenda-web-go)
To start a local development server, run:
Que lo disfrutes!
```bash
ng serve
```
🇺🇸
This web site is a remake of on the lessons from a web development course "Desarrollo Web Completo con HTML5, CSS3, JS AJAX PHP y MySQL" by Juan Pablo De La Torre Valdez, with the intention of intensively using newer and not so new tools offered by Angular. Aditionally the backend side has been developed using Go with the goal of developing proficiency and expetise with this language.
Once the server is running, open your browser and navigate to `http://localhost:4200/`. The application will automatically reload whenever you modify any of the source files.
You can take a look a the original site [here](https://agendaproject.epizy.com)
And it's repository [here](https://github.com/gabdlr/projects-AgendaWeb)
The backend code is in this [repository](https://gitea.gabilandia.com/gabdlr/agenda-web-go)
## Code scaffolding
Angular CLI includes powerful code scaffolding tools. To generate a new component, run:
```bash
ng generate component component-name
```
For a complete list of available schematics (such as `components`, `directives`, or `pipes`), run:
```bash
ng generate --help
```
## Building
To build the project run:
```bash
ng build
```
This will compile your project and store the build artifacts in the `dist/` directory. By default, the production build optimizes your application for performance and speed.
## Running unit tests
To execute unit tests with the [Karma](https://karma-runner.github.io) test runner, use the following command:
```bash
ng test
```
## Running end-to-end tests
For end-to-end (e2e) testing, run:
```bash
ng e2e
```
Angular CLI does not come with an end-to-end testing framework by default. You can choose one that suits your needs.
## Additional Resources
For more information on using the Angular CLI, including detailed command references, visit the [Angular CLI Overview and Command Reference](https://angular.dev/tools/cli) page.
Enjoy!

View File

@@ -3,7 +3,8 @@
"short_name": "Gabigenda",
"display": "standalone",
"scope": "./",
"background_color": "#ff0000",
"background_color": "#fefffa",
"theme_color": "#9c0a45",
"start_url": "./",
"icons": [
{

View File

@@ -3,19 +3,19 @@
<div class="fields">
<app-form-field
[errorsDictionary]="companyAndNameErrorsDictionary"
[errorsDictionary]="companyAndNameErrorsDictionary()"
formControlName="name"
[label]="(languageManager.strings.name|upperfirst) + ':'"
[placeholder]="languageManager.strings.contactsName|upperfirst"
/>
<app-form-field
[errorsDictionary]="companyAndNameErrorsDictionary"
[errorsDictionary]="companyAndNameErrorsDictionary()"
formControlName="company"
[label]="(languageManager.strings.company|upperfirst) + ':'"
[placeholder]="languageManager.strings.contactsCompany|upperfirst"
/>
<app-form-field
[errorsDictionary]="phoneErrorsDictionary"
[errorsDictionary]="phoneErrorsDictionary()"
formControlName="phone"
[label]="(languageManager.strings.phone|upperfirst) +':'"
[placeholder]="languageManager.strings.contactsPhone|upperfirst"

View File

@@ -12,7 +12,10 @@ describe('ContactForm', () => {
let languageManager: jasmine.SpyObj<LanguageManager>;
beforeEach(async () => {
languageManager = jasmine.createSpyObj(LanguageManager.name, [], { strings: strings.en });
languageManager = jasmine.createSpyObj(LanguageManager.name, [], {
strings: strings.en,
selectedLanguage$: () => 'en',
});
await TestBed.configureTestingModule({
imports: [ContactForm],

View File

@@ -26,6 +26,7 @@ export class ContactForm {
protected phoneErrorsDictionary = new PhoneFieldErroresDictionary().getDictionary();
handleSubmit(contactForm: ContactFormValue) {
if (this.form().invalid) return;
if (contactForm.company === null || contactForm.name === null || contactForm.phone === null)
return;
const contact = new ContactDTO(

View File

@@ -12,7 +12,7 @@
<div>
@for(error of errorsDictionary()|keyvalue; track error.key) {
@if(control.hasError(error.key) && isDirty){
<p class="error-text">• {{error.value}}</p>
<p class="error-text">• {{error.value|upperfirst}}</p>
}
}
</div>

View File

@@ -1,10 +1,11 @@
import { KeyValuePipe } from '@angular/common';
import { Component, computed, input, Optional, Self, signal } from '@angular/core';
import { ControlValueAccessor, NgControl, ReactiveFormsModule } from '@angular/forms';
import { UpperfirstPipe } from '../../pipes/upperfirst-pipe';
@Component({
selector: 'app-form-field',
imports: [ReactiveFormsModule, KeyValuePipe],
imports: [ReactiveFormsModule, KeyValuePipe, UpperfirstPipe],
templateUrl: './form-field.html',
styleUrl: './form-field.scss',
})

View File

@@ -1,18 +1,17 @@
import { inject } from '@angular/core';
import { computed, inject, Signal, signal } from '@angular/core';
import { Dictionary } from '../interfaces/dictionary.interface';
import { LanguageManager } from '../services/language-manager';
export class NameAndCompanyFieldsErrorsDictionary implements Dictionary {
private readonly languageManager = inject(LanguageManager);
private readonly maxlen: string;
private readonly required = this.languageManager.strings.errorMessageRequired;
constructor() {
this.maxlen = this.languageManager.strings.errorMessageMaxLength(120);
getDictionary(): Signal<{ [key: string]: string }> {
return computed(
() =>
this.languageManager.selectedLanguage$() && {
maxlen: this.languageManager.strings.errorMessageMaxLength(120),
required: this.languageManager.strings.errorMessageRequired,
}
getDictionary(): { [key: string]: string } {
const { maxlen, required } = this;
return { maxlen, required };
);
}
}

View File

@@ -1,14 +1,17 @@
import { inject } from '@angular/core';
import { computed, inject, Signal } from '@angular/core';
import { Dictionary } from '../interfaces/dictionary.interface';
import { LanguageManager } from '../services/language-manager';
export class PhoneFieldErroresDictionary implements Dictionary {
languageManager = inject(LanguageManager);
pattern = this.languageManager.strings.errorMessagePhonePattern;
required = this.languageManager.strings.errorMessageRequired;
getDictionary(): { [key: string]: string } {
const { required, pattern } = this;
return { required, pattern };
getDictionary(): Signal<{ [key: string]: string }> {
return computed(
() =>
this.languageManager.selectedLanguage$() && {
pattern: this.languageManager.strings.errorMessagePhonePattern,
required: this.languageManager.strings.errorMessageRequired,
}
);
}
}

View File

@@ -1,3 +1,5 @@
import { Signal } from '@angular/core';
export interface Dictionary {
getDictionary(): { [key: string]: string };
getDictionary(): Signal<{ [key: string]: string }>;
}

View File

@@ -21,12 +21,15 @@ describe('Edit', () => {
let CONTACT_MOCK: ContactDTO;
beforeEach(async () => {
CONTACT_MOCK = new ContactDTO(1, 'mock', 'mock', 'mock');
CONTACT_MOCK = new ContactDTO(1, 'mock', 'mock', '123456789012');
activatedRoute = jasmine.createSpyObj(ActivatedRoute.name, [], {
data: of({ contact: CONTACT_MOCK }),
});
contactService = jasmine.createSpyObj(ContactService.name, ['update']);
languageManager = jasmine.createSpyObj(LanguageManager.name, [], { strings: strings.en });
languageManager = jasmine.createSpyObj(LanguageManager.name, [], {
strings: strings.en,
selectedLanguage$: () => 'en',
});
router = jasmine.createSpyObj(Router.name, ['navigate']);
await TestBed.configureTestingModule({

View File

@@ -15,15 +15,15 @@ export const strings = Object.freeze({
editContact: 'edit contact',
editContactSuccessNotification: 'contact edited successfully',
editTheContact: 'edit the contact',
errorMessageMaxLength: (maxLen: number) => `Must be ${maxLen} characters or fewer.`,
errorMessagePhonePattern: `Valid format: + (optional) plus 12 to 15 digits`,
errorMessageRequired: 'This field is required.',
errorNotification: 'Oops, there was an error',
errorMessageMaxLength: (maxLen: number) => `must be ${maxLen} characters or fewer`,
errorMessagePhonePattern: `valid format: + (optional) plus 12 to 15 digits`,
errorMessageRequired: 'this field is required',
errorNotification: 'oops, there was an error',
goBack: 'go back',
name: 'name',
phone: 'phone',
save: 'save',
searchContactPlaceholder: 'Search contact...',
searchContactPlaceholder: 'search contact...',
},
es: {
actions: 'acciones',
@@ -41,9 +41,9 @@ export const strings = Object.freeze({
editContact: 'editar contacto',
editContactSuccessNotification: 'contacto editado correctamente',
editTheContact: 'edite el contacto. ',
errorMessageMaxLength: (maxLen: number) => `Debe contener ${maxLen} caracteres or menos.`,
errorMessagePhonePattern: `Formato: + (opcional) y 12 a 15 digitos`,
errorMessageRequired: 'este campo es requerido.',
errorMessageMaxLength: (maxLen: number) => `debe contener ${maxLen} caracteres or menos`,
errorMessagePhonePattern: `formato: + (opcional) y 12 a 15 digitos`,
errorMessageRequired: 'este campo es requerido',
errorNotification: 'hubo un error',
goBack: 'volver',
name: 'nombre',

View File

@@ -1,4 +1,4 @@
export const environment = {
prod: false,
apiUrl: 'http://192.168.1.3:4444',
apiUrl: 'http://192.168.1.3:8080',
};