├── src ├── assets │ └── .gitkeep ├── app │ ├── app.component.scss │ ├── pages │ │ └── users │ │ │ ├── user-add │ │ │ ├── user-add.component.scss │ │ │ ├── user-add.component.spec.ts │ │ │ ├── user-add.component.html │ │ │ └── user-add.component.ts │ │ │ ├── user-edit │ │ │ ├── user-edit.component.scss │ │ │ ├── user-edit.component.spec.ts │ │ │ ├── user-edit.component.html │ │ │ └── user-edit.component.ts │ │ │ ├── user-list │ │ │ ├── user-list.component.scss │ │ │ ├── user-list.component.spec.ts │ │ │ ├── user-list.component.html │ │ │ └── user-list.component.ts │ │ │ └── users.routes.ts │ ├── app.component.html │ ├── commons │ │ └── interfaces │ │ │ └── player.interface.ts │ ├── app.routes.ts │ ├── app.component.ts │ ├── app.component.spec.ts │ └── services │ │ └── players.service.ts ├── styles.scss ├── favicon.ico ├── enviroments │ └── enviroment.ts ├── index.html └── main.ts ├── .vscode ├── extensions.json ├── launch.json └── tasks.json ├── .firebaserc ├── tsconfig.app.json ├── tsconfig.spec.json ├── .editorconfig ├── .gitignore ├── firebase.json ├── tsconfig.json ├── README.md ├── package.json └── angular.json /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/pages/users/user-add/user-add.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/pages/users/user-edit/user-edit.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/pages/users/user-list/user-list.component.scss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kevindaviladev/angular-crud-v15-standalone-firebase/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=827846 3 | "recommendations": ["angular.ng-template"] 4 | } 5 | -------------------------------------------------------------------------------- /src/app/commons/interfaces/player.interface.ts: -------------------------------------------------------------------------------- 1 | export interface Player { 2 | id: string; 3 | name: string; 4 | decks: Deck[]; 5 | } 6 | 7 | interface Deck { 8 | name: string; 9 | cards: number; 10 | } 11 | -------------------------------------------------------------------------------- /.firebaserc: -------------------------------------------------------------------------------- 1 | { 2 | "targets": { 3 | "crudv15": { 4 | "hosting": { 5 | "scCrud": [ 6 | "crudv15" 7 | ] 8 | } 9 | } 10 | }, 11 | "projects": { 12 | "default": "crudv15" 13 | } 14 | } -------------------------------------------------------------------------------- /src/app/app.routes.ts: -------------------------------------------------------------------------------- 1 | import { Routes } from '@angular/router'; 2 | 3 | export const appRoutes: Routes = [ 4 | { path: '', redirectTo: 'users', pathMatch: 'full' }, 5 | { 6 | path: 'users', 7 | loadChildren: () => 8 | import('./pages/users/users.routes').then((routes) => routes.UserRoutes), 9 | }, 10 | ]; 11 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/app", 6 | "types": [] 7 | }, 8 | "files": [ 9 | "src/main.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "extends": "./tsconfig.json", 4 | "compilerOptions": { 5 | "outDir": "./out-tsc/spec", 6 | "types": [ 7 | "jasmine" 8 | ] 9 | }, 10 | "include": [ 11 | "src/**/*.spec.ts", 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.ts] 12 | quote_type = single 13 | 14 | [*.md] 15 | max_line_length = off 16 | trim_trailing_whitespace = false 17 | -------------------------------------------------------------------------------- /src/enviroments/enviroment.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | firebase: { 3 | apiKey: 'AIzaSyDopYomECtF1H5cKJ9RtH9QALRi5myys-M', 4 | authDomain: 'crudv15.firebaseapp.com', 5 | projectId: 'crudv15', 6 | storageBucket: 'crudv15.appspot.com', 7 | messagingSenderId: '403199801800', 8 | appId: '1:403199801800:web:8dcc7dc362807319e468fd', 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { RouterModule } from '@angular/router'; 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | standalone: true, 7 | imports: [RouterModule], 8 | templateUrl: './app.component.html', 9 | styleUrls: ['./app.component.scss'], 10 | }) 11 | export class AppComponent { 12 | title = 'scCrud'; 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 3 | "version": "0.2.0", 4 | "configurations": [ 5 | { 6 | "name": "ng serve", 7 | "type": "pwa-chrome", 8 | "request": "launch", 9 | "preLaunchTask": "npm: start", 10 | "url": "http://localhost:4200/" 11 | }, 12 | { 13 | "name": "ng test", 14 | "type": "chrome", 15 | "request": "launch", 16 | "preLaunchTask": "npm: test", 17 | "url": "http://localhost:9876/debug.html" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/app/pages/users/users.routes.ts: -------------------------------------------------------------------------------- 1 | import { Route } from '@angular/router'; 2 | import { UserAddComponent } from './user-add/user-add.component'; 3 | import { UserEditComponent } from './user-edit/user-edit.component'; 4 | import { UserListComponent } from './user-list/user-list.component'; 5 | 6 | export const UserRoutes: Route[] = [ 7 | { 8 | path: '', 9 | title: 'User list', 10 | component: UserListComponent, 11 | }, 12 | { 13 | path: 'add', 14 | title: 'Add new user', 15 | component: UserAddComponent, 16 | }, 17 | { 18 | path: 'edit', 19 | title: 'Edit user', 20 | component: UserEditComponent, 21 | }, 22 | ]; 23 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ScCrud 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/app/pages/users/user-add/user-add.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserAddComponent } from './user-add.component'; 4 | 5 | describe('UserAddComponent', () => { 6 | let component: UserAddComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ UserAddComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(UserAddComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/pages/users/user-edit/user-edit.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserEditComponent } from './user-edit.component'; 4 | 5 | describe('UserEditComponent', () => { 6 | let component: UserEditComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ UserEditComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(UserEditComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /src/app/pages/users/user-list/user-list.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { UserListComponent } from './user-list.component'; 4 | 5 | describe('UserListComponent', () => { 6 | let component: UserListComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async () => { 10 | await TestBed.configureTestingModule({ 11 | imports: [ UserListComponent ] 12 | }) 13 | .compileComponents(); 14 | 15 | fixture = TestBed.createComponent(UserListComponent); 16 | component = fixture.componentInstance; 17 | fixture.detectChanges(); 18 | }); 19 | 20 | it('should create', () => { 21 | expect(component).toBeTruthy(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # Compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | /bazel-out 8 | 9 | # Node 10 | /node_modules 11 | npm-debug.log 12 | yarn-error.log 13 | 14 | # IDEs and editors 15 | .idea/ 16 | .project 17 | .classpath 18 | .c9/ 19 | *.launch 20 | .settings/ 21 | *.sublime-workspace 22 | 23 | # Visual Studio Code 24 | .vscode/* 25 | !.vscode/settings.json 26 | !.vscode/tasks.json 27 | !.vscode/launch.json 28 | !.vscode/extensions.json 29 | .history/* 30 | 31 | # Miscellaneous 32 | /.angular/cache 33 | .sass-cache/ 34 | /connect.lock 35 | /coverage 36 | /libpeerconnection.log 37 | testem.log 38 | /typings 39 | 40 | # System files 41 | .DS_Store 42 | Thumbs.db 43 | 44 | # Firebase 45 | .firebase 46 | *-debug.log 47 | .runtimeconfig.json 48 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { importProvidersFrom } from '@angular/core'; 2 | import { bootstrapApplication } from '@angular/platform-browser'; 3 | import { provideRouter } from '@angular/router'; 4 | import { AppComponent } from './app/app.component'; 5 | import { HttpClientModule } from '@angular/common/http'; 6 | import { appRoutes } from './app/app.routes'; 7 | import { initializeApp, provideFirebaseApp } from '@angular/fire/app'; 8 | import { getFirestore, provideFirestore } from '@angular/fire/firestore'; 9 | import { environment } from './enviroments/enviroment'; 10 | 11 | bootstrapApplication(AppComponent, { 12 | providers: [ 13 | provideRouter(appRoutes), 14 | importProvidersFrom(HttpClientModule), 15 | importProvidersFrom( 16 | provideFirebaseApp(() => initializeApp(environment.firebase)) 17 | ), 18 | importProvidersFrom(provideFirestore(() => getFirestore())), 19 | ], 20 | }); 21 | -------------------------------------------------------------------------------- /firebase.json: -------------------------------------------------------------------------------- 1 | { 2 | "hosting": { 3 | "target": "scCrud", 4 | "public": "dist/sc-crud", 5 | "ignore": [ 6 | "**/.*" 7 | ], 8 | "headers": [ 9 | { 10 | "source": "*.[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f].+(css|js)", 11 | "headers": [ 12 | { 13 | "key": "Cache-Control", 14 | "value": "public,max-age=31536000,immutable" 15 | } 16 | ] 17 | }, 18 | { 19 | "source": "/@(ngsw-worker.js|ngsw.json)", 20 | "headers": [ 21 | { 22 | "key": "Cache-Control", 23 | "value": "no-cache" 24 | } 25 | ] 26 | } 27 | ], 28 | "rewrites": [ 29 | { 30 | "source": "**", 31 | "destination": "/index.html" 32 | } 33 | ] 34 | } 35 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | /* To learn more about this file see: https://angular.io/config/tsconfig. */ 2 | { 3 | "compileOnSave": false, 4 | "compilerOptions": { 5 | "baseUrl": "./", 6 | "outDir": "./dist/out-tsc", 7 | "forceConsistentCasingInFileNames": true, 8 | "strict": true, 9 | "noImplicitOverride": true, 10 | "noPropertyAccessFromIndexSignature": true, 11 | "noImplicitReturns": true, 12 | "noFallthroughCasesInSwitch": true, 13 | "sourceMap": true, 14 | "declaration": false, 15 | "downlevelIteration": true, 16 | "experimentalDecorators": true, 17 | "moduleResolution": "node", 18 | "importHelpers": true, 19 | "target": "ES2022", 20 | "module": "ES2022", 21 | "useDefineForClassFields": false, 22 | "lib": [ 23 | "ES2022", 24 | "dom" 25 | ] 26 | }, 27 | "angularCompilerOptions": { 28 | "enableI18nLegacyMessageIdFormat": false, 29 | "strictInjectionParameters": true, 30 | "strictInputAccessModifiers": true, 31 | "strictTemplates": true 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // For more information, visit: https://go.microsoft.com/fwlink/?LinkId=733558 3 | "version": "2.0.0", 4 | "tasks": [ 5 | { 6 | "type": "npm", 7 | "script": "start", 8 | "isBackground": true, 9 | "problemMatcher": { 10 | "owner": "typescript", 11 | "pattern": "$tsc", 12 | "background": { 13 | "activeOnStart": true, 14 | "beginsPattern": { 15 | "regexp": "(.*?)" 16 | }, 17 | "endsPattern": { 18 | "regexp": "bundle generation complete" 19 | } 20 | } 21 | } 22 | }, 23 | { 24 | "type": "npm", 25 | "script": "test", 26 | "isBackground": true, 27 | "problemMatcher": { 28 | "owner": "typescript", 29 | "pattern": "$tsc", 30 | "background": { 31 | "activeOnStart": true, 32 | "beginsPattern": { 33 | "regexp": "(.*?)" 34 | }, 35 | "endsPattern": { 36 | "regexp": "bundle generation complete" 37 | } 38 | } 39 | } 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ScCrud 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 15.0.2. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The application will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via a platform of your choice. To use this command, you need to first add a package that implements end-to-end testing capabilities. 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI Overview and Command Reference](https://angular.io/cli) page. 28 | -------------------------------------------------------------------------------- /src/app/pages/users/user-list/user-list.component.html: -------------------------------------------------------------------------------- 1 | 2 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 31 | 32 | 33 |
#NombreDecksAcciones
{{ i }}{{ player.name }} 23 |
  • 24 | {{ deck.name }} - {{ deck.cards }} cartas 25 |
  • 26 |
    28 | 29 | 30 |
    34 |
    35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sc-crud", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch --configuration development", 9 | "test": "ng test" 10 | }, 11 | "private": true, 12 | "dependencies": { 13 | "@angular/animations": "^15.0.0", 14 | "@angular/common": "^15.0.0", 15 | "@angular/compiler": "^15.0.0", 16 | "@angular/core": "^15.0.0", 17 | "@angular/fire": "^7.5.0", 18 | "@angular/forms": "^15.0.0", 19 | "@angular/platform-browser": "^15.0.0", 20 | "@angular/platform-browser-dynamic": "^15.0.0", 21 | "@angular/router": "^15.0.0", 22 | "rxjs": "~7.5.0", 23 | "tslib": "^2.3.0", 24 | "zone.js": "~0.12.0" 25 | }, 26 | "devDependencies": { 27 | "@angular-devkit/build-angular": "^15.0.2", 28 | "@angular/cli": "~15.0.2", 29 | "@angular/compiler-cli": "^15.0.0", 30 | "@types/jasmine": "~4.3.0", 31 | "jasmine-core": "~4.5.0", 32 | "karma": "~6.4.0", 33 | "karma-chrome-launcher": "~3.1.0", 34 | "karma-coverage": "~2.2.0", 35 | "karma-jasmine": "~5.1.0", 36 | "karma-jasmine-html-reporter": "~2.0.0", 37 | "typescript": "~4.8.2" 38 | } 39 | } -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { TestBed } from '@angular/core/testing'; 2 | import { RouterTestingModule } from '@angular/router/testing'; 3 | import { AppComponent } from './app.component'; 4 | 5 | describe('AppComponent', () => { 6 | beforeEach(async () => { 7 | await TestBed.configureTestingModule({ 8 | imports: [ 9 | RouterTestingModule 10 | ], 11 | declarations: [ 12 | AppComponent 13 | ], 14 | }).compileComponents(); 15 | }); 16 | 17 | it('should create the app', () => { 18 | const fixture = TestBed.createComponent(AppComponent); 19 | const app = fixture.componentInstance; 20 | expect(app).toBeTruthy(); 21 | }); 22 | 23 | it(`should have as title 'scCrud'`, () => { 24 | const fixture = TestBed.createComponent(AppComponent); 25 | const app = fixture.componentInstance; 26 | expect(app.title).toEqual('scCrud'); 27 | }); 28 | 29 | it('should render title', () => { 30 | const fixture = TestBed.createComponent(AppComponent); 31 | fixture.detectChanges(); 32 | const compiled = fixture.nativeElement as HTMLElement; 33 | expect(compiled.querySelector('.content span')?.textContent).toContain('scCrud app is running!'); 34 | }); 35 | }); 36 | -------------------------------------------------------------------------------- /src/app/pages/users/user-add/user-add.component.html: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 | 11 | 12 |
    13 |
    18 | 19 |
    20 | 21 | 28 |
    29 |
    30 | 31 | 38 |
    39 | 40 |
    41 | 42 | 43 | -------------------------------------------------------------------------------- /src/app/pages/users/user-edit/user-edit.component.html: -------------------------------------------------------------------------------- 1 |
    2 |

    Editar jugador

    3 |
    4 | 5 | 12 | 15 |
    16 |
    21 | 22 |
    23 | 24 | 31 |
    32 |
    33 | 34 | 41 |
    42 | 43 |
    44 | 45 | 46 | 53 | -------------------------------------------------------------------------------- /src/app/pages/users/user-add/user-add.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { 4 | FormArray, 5 | FormControl, 6 | FormGroup, 7 | ReactiveFormsModule, 8 | Validators, 9 | } from '@angular/forms'; 10 | import { PlayersService } from 'src/app/services/players.service'; 11 | import { Player } from 'src/app/commons/interfaces/player.interface'; 12 | import { Router } from '@angular/router'; 13 | 14 | @Component({ 15 | selector: 'app-user-add', 16 | standalone: true, 17 | imports: [CommonModule, ReactiveFormsModule], 18 | templateUrl: './user-add.component.html', 19 | styleUrls: ['./user-add.component.scss'], 20 | }) 21 | export class UserAddComponent { 22 | _playerService = inject(PlayersService); 23 | _router = inject(Router); 24 | 25 | form = new FormGroup({ 26 | name: new FormControl('', Validators.required), 27 | decks: new FormArray([]), 28 | }); 29 | 30 | createDeck() { 31 | (this.form.get('decks') as FormArray).push( 32 | new FormGroup({ 33 | name: new FormControl('', Validators.required), 34 | cards: new FormControl(null, Validators.required), 35 | }) 36 | ); 37 | } 38 | 39 | addPlayer() { 40 | this._playerService.addPlayer({ 41 | id: new Date().getTime().toString(), 42 | ...this.form.getRawValue(), 43 | } as Player); 44 | this._router.navigate(['users']); 45 | } 46 | 47 | get decks() { 48 | return (this.form.get('decks') as FormArray).controls; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/app/pages/users/user-list/user-list.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject, OnInit } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { Player } from 'src/app/commons/interfaces/player.interface'; 4 | import { debounceTime, Observable } from 'rxjs'; 5 | import { PlayersService } from 'src/app/services/players.service'; 6 | import { FormControl, ReactiveFormsModule } from '@angular/forms'; 7 | import { Router } from '@angular/router'; 8 | 9 | @Component({ 10 | selector: 'app-user-list', 11 | standalone: true, 12 | imports: [ 13 | CommonModule, 14 | ReactiveFormsModule, 15 | // NgIf, NgFor, AsyncPipe 16 | ], 17 | templateUrl: './user-list.component.html', 18 | styleUrls: ['./user-list.component.scss'], 19 | }) 20 | export class UserListComponent implements OnInit { 21 | players$!: Observable; 22 | _playerService = inject(PlayersService); 23 | _router = inject(Router); 24 | searcher = new FormControl(''); 25 | 26 | ngOnInit(): void { 27 | this.players$ = this._playerService.getPlayers(); 28 | this.searcher.valueChanges.pipe(debounceTime(1000)).subscribe((search) => { 29 | // this._playerService. 30 | if (search) { 31 | console.log(search); 32 | this.players$ = this._playerService.getPlayers(search); 33 | } else { 34 | this.players$ = this._playerService.getPlayers(); 35 | } 36 | }); 37 | } 38 | 39 | editPlayer(player: Player) { 40 | this._router.navigateByUrl('users/edit', { state: { player } }); 41 | } 42 | deletePlayer(player: Player) { 43 | if (confirm(`Seguro de borrar a ${player.name}`)) { 44 | this._playerService.deletePlayer(player.id); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/app/services/players.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { 3 | addDoc, 4 | collectionData, 5 | deleteDoc, 6 | doc, 7 | Firestore, 8 | getDoc, 9 | query, 10 | updateDoc, 11 | where, 12 | } from '@angular/fire/firestore'; 13 | import { collection, getDocs } from '@firebase/firestore'; 14 | import { BehaviorSubject, Observable, of } from 'rxjs'; 15 | import { Player } from '../commons/interfaces/player.interface'; 16 | 17 | @Injectable({ 18 | providedIn: 'root', 19 | }) 20 | export class PlayersService { 21 | private playerSource = new BehaviorSubject(null); 22 | players$ = this.playerSource.asObservable(); 23 | 24 | constructor(private firestore: Firestore) {} 25 | 26 | addPlayer(player: Player) { 27 | const playersRef = collection(this.firestore, 'players'); 28 | return addDoc(playersRef, player); 29 | } 30 | 31 | getPlayers(filter = '') { 32 | const playersRef = collection(this.firestore, 'players'); 33 | let q = query(playersRef); 34 | if (filter) { 35 | q = query(playersRef, where('name', '==', filter)); 36 | } 37 | return collectionData(q) as unknown as Observable; 38 | } 39 | 40 | async updatePlayer(player: Player) { 41 | const playersRef = collection(this.firestore, 'players'); 42 | let q = query(playersRef, where('id', '==', player.id)); 43 | const querySnapshot = await getDocs(q); 44 | 45 | querySnapshot.forEach(async (document) => { 46 | const docRef = doc(this.firestore, 'players', document.id); 47 | await updateDoc(docRef, { ...player }); 48 | }); 49 | } 50 | 51 | async deletePlayer(id: string) { 52 | const playersRef = collection(this.firestore, 'players'); 53 | let q = query(playersRef, where('id', '==', id)); 54 | const querySnapshot = await getDocs(q); 55 | 56 | querySnapshot.forEach(async (document) => { 57 | const docRef = doc(this.firestore, 'players', document.id); 58 | deleteDoc(docRef); 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/app/pages/users/user-edit/user-edit.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, inject } from '@angular/core'; 2 | import { CommonModule, Location } from '@angular/common'; 3 | import { 4 | FormArray, 5 | FormControl, 6 | FormGroup, 7 | ReactiveFormsModule, 8 | Validators, 9 | } from '@angular/forms'; 10 | import { PlayersService } from 'src/app/services/players.service'; 11 | import { Player } from 'src/app/commons/interfaces/player.interface'; 12 | import { Router } from '@angular/router'; 13 | 14 | @Component({ 15 | selector: 'app-user-edit', 16 | standalone: true, 17 | imports: [CommonModule, ReactiveFormsModule], 18 | templateUrl: './user-edit.component.html', 19 | styleUrls: ['./user-edit.component.scss'], 20 | }) 21 | export class UserEditComponent { 22 | _location = inject(Location); 23 | _playerService = inject(PlayersService); 24 | _router = inject(Router); 25 | player!: Player; 26 | 27 | form = new FormGroup({ 28 | name: new FormControl('', Validators.required), 29 | decks: new FormArray([]), 30 | }); 31 | 32 | ngOnInit() { 33 | console.log(this._location.getState()); 34 | this.player = (this._location.getState() as any).player as Player; 35 | if (this.player) this.setCurrentPlayer(this.player); 36 | } 37 | 38 | createDeck() { 39 | (this.form.get('decks') as FormArray).push( 40 | new FormGroup({ 41 | name: new FormControl('', Validators.required), 42 | cards: new FormControl(null, Validators.required), 43 | }) 44 | ); 45 | } 46 | 47 | setCurrentPlayer(player: any) { 48 | this.form.patchValue(player); 49 | player.decks.map((deck: any) => { 50 | const deckForm = new FormGroup({ 51 | name: new FormControl(deck.name), 52 | cards: new FormControl(deck.cards), 53 | }); 54 | (this.form.get('decks') as FormArray).push(deckForm); 55 | }); 56 | } 57 | 58 | get decks() { 59 | return (this.form.get('decks') as FormArray).controls; 60 | } 61 | 62 | updatePlayer() { 63 | console.log({ 64 | id: this.player.id, 65 | ...this.form.getRawValue(), 66 | }); 67 | 68 | this._playerService.updatePlayer({ 69 | id: this.player.id, 70 | ...this.form.getRawValue(), 71 | } as Player); 72 | this._router.navigate(['users']); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "scCrud": { 7 | "projectType": "application", 8 | "schematics": { 9 | "@schematics/angular:component": { 10 | "style": "scss" 11 | } 12 | }, 13 | "root": "", 14 | "sourceRoot": "src", 15 | "prefix": "app", 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/sc-crud", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": [ 24 | "zone.js" 25 | ], 26 | "tsConfig": "tsconfig.app.json", 27 | "inlineStyleLanguage": "scss", 28 | "assets": [ 29 | "src/favicon.ico", 30 | "src/assets" 31 | ], 32 | "styles": [ 33 | "src/styles.scss" 34 | ], 35 | "scripts": [] 36 | }, 37 | "configurations": { 38 | "production": { 39 | "budgets": [ 40 | { 41 | "type": "initial", 42 | "maximumWarning": "500kb", 43 | "maximumError": "1mb" 44 | }, 45 | { 46 | "type": "anyComponentStyle", 47 | "maximumWarning": "2kb", 48 | "maximumError": "4kb" 49 | } 50 | ], 51 | "outputHashing": "all" 52 | }, 53 | "development": { 54 | "buildOptimizer": false, 55 | "optimization": false, 56 | "vendorChunk": true, 57 | "extractLicenses": false, 58 | "sourceMap": true, 59 | "namedChunks": true 60 | } 61 | }, 62 | "defaultConfiguration": "production" 63 | }, 64 | "serve": { 65 | "builder": "@angular-devkit/build-angular:dev-server", 66 | "configurations": { 67 | "production": { 68 | "browserTarget": "scCrud:build:production" 69 | }, 70 | "development": { 71 | "browserTarget": "scCrud:build:development" 72 | } 73 | }, 74 | "defaultConfiguration": "development" 75 | }, 76 | "extract-i18n": { 77 | "builder": "@angular-devkit/build-angular:extract-i18n", 78 | "options": { 79 | "browserTarget": "scCrud:build" 80 | } 81 | }, 82 | "test": { 83 | "builder": "@angular-devkit/build-angular:karma", 84 | "options": { 85 | "polyfills": [ 86 | "zone.js", 87 | "zone.js/testing" 88 | ], 89 | "tsConfig": "tsconfig.spec.json", 90 | "inlineStyleLanguage": "scss", 91 | "assets": [ 92 | "src/favicon.ico", 93 | "src/assets" 94 | ], 95 | "styles": [ 96 | "src/styles.scss" 97 | ], 98 | "scripts": [] 99 | } 100 | }, 101 | "deploy": { 102 | "builder": "@angular/fire:deploy", 103 | "options": { 104 | "prerender": false, 105 | "ssr": false, 106 | "browserTarget": "scCrud:build:production", 107 | "firebaseProject": "crudv15", 108 | "firebaseHostingSite": "crudv15" 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } --------------------------------------------------------------------------------