diff --git a/apps/devmx/src/app/app.config.ts b/apps/devmx/src/app/app.config.ts index e0ac102d..0dac00a3 100644 --- a/apps/devmx/src/app/app.config.ts +++ b/apps/devmx/src/app/app.config.ts @@ -31,7 +31,9 @@ import { withViewTransitions, } from '@angular/router'; import { + HttpBackend, HttpClient, + HttpXhrBackend, provideHttpClient, withInterceptors, } from '@angular/common/http'; @@ -68,6 +70,10 @@ export const appConfig: ApplicationConfig = { }, provideLayout(appSections), provideHttpClient(withInterceptors([authInterceptor, loaderInterceptor])), + { + provide: HttpBackend, + useExisting: HttpXhrBackend, + }, provideHttpClientImpl(HttpClient), ...provideAccount(), provideLayoutToolbar(AuthenticationFacade), diff --git a/packages/account/ui-shared/src/lib/components/index.ts b/packages/account/ui-shared/src/lib/components/index.ts index 7a426e6f..48a6c5f3 100644 --- a/packages/account/ui-shared/src/lib/components/index.ts +++ b/packages/account/ui-shared/src/lib/components/index.ts @@ -1,5 +1,6 @@ -export * from './user-complete/user-complete.component'; export * from './user-card-skills/user-card-skills.component'; +export * from './user-complete/user-complete.component'; +export * from './search-user/search-user.component'; export * from './code-field/code-field.component'; export * from './user-roles/user-roles.component'; export * from './user-card/user-card.component'; diff --git a/packages/account/ui-shared/src/lib/components/search-user/search-user.component.html b/packages/account/ui-shared/src/lib/components/search-user/search-user.component.html new file mode 100644 index 00000000..77ab0bf3 --- /dev/null +++ b/packages/account/ui-shared/src/lib/components/search-user/search-user.component.html @@ -0,0 +1,18 @@ + + {{ label() }} + + {{ hint() }} + + @if (userFacade.response$ | async; as response) { + + @for (option of response.data; track option.id) { + {{ option.displayName }} + } + + } + + diff --git a/packages/account/ui-shared/src/lib/components/search-user/search-user.component.scss b/packages/account/ui-shared/src/lib/components/search-user/search-user.component.scss new file mode 100644 index 00000000..bac68ec2 --- /dev/null +++ b/packages/account/ui-shared/src/lib/components/search-user/search-user.component.scss @@ -0,0 +1,5 @@ +:host { + flex: 1; + display: flex; + flex-direction: column; +} diff --git a/packages/account/ui-shared/src/lib/components/search-user/search-user.component.ts b/packages/account/ui-shared/src/lib/components/search-user/search-user.component.ts new file mode 100644 index 00000000..6286da74 --- /dev/null +++ b/packages/account/ui-shared/src/lib/components/search-user/search-user.component.ts @@ -0,0 +1,65 @@ +import { MatAutocompleteModule } from '@angular/material/autocomplete'; +import { FormControl, ReactiveFormsModule } from '@angular/forms'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { MatInputModule } from '@angular/material/input'; +import { UserFacade } from '@devmx/account-data-access'; +import { User } from '@devmx/shared-api-interfaces'; +import { AsyncPipe } from '@angular/common'; +import { debounceTime, filter, startWith } from 'rxjs'; +import { + input, + inject, + output, + Component, + ChangeDetectionStrategy, +} from '@angular/core'; + +@Component({ + selector: 'devmx-search-user', + templateUrl: './search-user.component.html', + styleUrl: './search-user.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, + imports: [ + ReactiveFormsModule, + MatAutocompleteModule, + MatFormFieldModule, + MatInputModule, + AsyncPipe, + ], +}) +export class SearchUserComponent { + userFacade = inject(UserFacade); + + selected = output(); + + label = input('Usuário'); + + hint = input(''); + + control = new FormControl(''); + + constructor() { + this.control.valueChanges + .pipe( + startWith(' '), + filter((value) => typeof value === 'string'), + filter((value) => value.length > 0), + takeUntilDestroyed(), + debounceTime(400) + ) + .subscribe((displayName) => { + this.userFacade.setFilter({ displayName }); + this.userFacade.load(); + }); + } + + displayFn(user: User) { + return user && user.displayName ? user.displayName : ''; + } + + onOptionSelected(user: User) { + this.selected.emit(user); + this.control.setValue(''); + } +} diff --git a/packages/album/feature-admin/src/lib/containers/my-albums/my-albums.container.ts b/packages/album/feature-admin/src/lib/containers/my-albums/my-albums.container.ts index 94050939..0b8aa71f 100644 --- a/packages/album/feature-admin/src/lib/containers/my-albums/my-albums.container.ts +++ b/packages/album/feature-admin/src/lib/containers/my-albums/my-albums.container.ts @@ -8,12 +8,13 @@ import { DialogFacade } from '@devmx/shared-ui-global/dialog'; import { MatTooltipModule } from '@angular/material/tooltip'; import { IconComponent } from '@devmx/shared-ui-global/icon'; import { AlbumCardComponent } from '@devmx/album-ui-shared'; +import { SheetFacade } from '@devmx/shared-ui-global/sheet'; import { MatButtonModule } from '@angular/material/button'; import { combineLatest, filter, map, take } from 'rxjs'; import { AlbumFacade } from '@devmx/album-data-access'; import { Album } from '@devmx/shared-api-interfaces'; +import { CreateAlbumSheet } from '../../sheets'; import { AsyncPipe } from '@angular/common'; -import { AlbumForm } from '../../forms'; @Component({ selector: 'devmx-admin-my-albums', @@ -38,6 +39,8 @@ export class MyAlbumsContainer { dialogFacade = inject(DialogFacade); + sheetFacade = inject(SheetFacade); + authFacade = inject(AuthenticationFacade); albumFacade = inject(AlbumFacade); @@ -74,15 +77,17 @@ export class MyAlbumsContainer { } createAlbum() { - const form = new AlbumForm(); - - form.patchValue({ title: new Date().toLocaleDateString() }); - - const request$ = this.albumFacade.create(form.getRawValue()); - - request$.pipe(take(1)).subscribe((album) => { - this.router.navigate([album.id], { relativeTo: this.route }); - }); + this.sheetFacade + .open(CreateAlbumSheet) + .pipe(take(1)) + .subscribe((value) => { + if (value) { + const request$ = this.albumFacade.create(value); + request$.pipe(take(1)).subscribe((album) => { + this.router.navigate([album.id], { relativeTo: this.route }); + }); + } + }); } deleteAlbum({ id, title }: Album) { diff --git a/packages/album/feature-admin/src/lib/forms/album.ts b/packages/album/feature-admin/src/lib/forms/album.ts index 1f64bfb1..c5df62dc 100644 --- a/packages/album/feature-admin/src/lib/forms/album.ts +++ b/packages/album/feature-admin/src/lib/forms/album.ts @@ -19,7 +19,7 @@ export class AlbumForm extends FormGroup> { id: new FormControl('', { nonNullable: true, }), - title: new FormControl(new Date().toLocaleDateString(), { + title: new FormControl('', { nonNullable: true, validators: [Validators.required], }), diff --git a/packages/album/feature-admin/src/lib/sheets/create-album/create-album.sheet.html b/packages/album/feature-admin/src/lib/sheets/create-album/create-album.sheet.html new file mode 100644 index 00000000..b0fa762d --- /dev/null +++ b/packages/album/feature-admin/src/lib/sheets/create-album/create-album.sheet.html @@ -0,0 +1,41 @@ +
+ + Título do album + + Obrigatório + + + +

Contribuidores

+ + @for (control of form.contributors.controls; track control.value; let index + = $index) { + + + + {{control.value.displayName}} + + + + } +
+ + + +
+ + + +
+ diff --git a/packages/album/feature-admin/src/lib/sheets/create-album/create-album.sheet.scss b/packages/album/feature-admin/src/lib/sheets/create-album/create-album.sheet.scss new file mode 100644 index 00000000..94b6153e --- /dev/null +++ b/packages/album/feature-admin/src/lib/sheets/create-album/create-album.sheet.scss @@ -0,0 +1,19 @@ +:host { + display: flex; + padding: 1.5em 1em 0.5em; + flex-direction: column; + + form { + flex: 1; + gap: 1em; + display: flex; + flex-direction: column; + } + + footer { + margin-top: 1em; + display: flex; + flex-direction: row-reverse; + justify-content: space-between; + } +} diff --git a/packages/album/feature-admin/src/lib/sheets/create-album/create-album.sheet.ts b/packages/album/feature-admin/src/lib/sheets/create-album/create-album.sheet.ts new file mode 100644 index 00000000..45b8679e --- /dev/null +++ b/packages/album/feature-admin/src/lib/sheets/create-album/create-album.sheet.ts @@ -0,0 +1,57 @@ +import { OnInit, Component, ChangeDetectionStrategy } from '@angular/core'; +import { MatBottomSheetModule } from '@angular/material/bottom-sheet'; +import { EditableAlbum, UserRef } from '@devmx/shared-api-interfaces'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { SheetComponent } from '@devmx/shared-ui-global/sheet'; +import { IconComponent } from '@devmx/shared-ui-global/icon'; +import { MatButtonModule } from '@angular/material/button'; +import { MatInputModule } from '@angular/material/input'; +import { MatListModule } from '@angular/material/list'; +import { ReactiveFormsModule } from '@angular/forms'; +import { AlbumForm } from '../../forms'; +import { + provideSelectUser, + SearchUserComponent, +} from '@devmx/account-ui-shared'; + +@Component({ + selector: 'devmx-create-album', + templateUrl: './create-album.sheet.html', + styleUrl: './create-album.sheet.scss', + changeDetection: ChangeDetectionStrategy.OnPush, + providers: [provideSelectUser()], + imports: [ + SearchUserComponent, + MatBottomSheetModule, + ReactiveFormsModule, + MatFormFieldModule, + MatButtonModule, + MatInputModule, + MatListModule, + IconComponent, + ], +}) +export class CreateAlbumSheet + extends SheetComponent + implements OnInit +{ + form = new AlbumForm(); + + ngOnInit() { + if (this.data) { + this.form.patch(this.data); + } + } + + onContributorSelected(user: UserRef) { + this.form.contributors.add(user); + } + + onSubmit() { + if (this.form.valid) { + return this.close(this.form.getRawValue()); + } + + return this.form.markAllAsTouched(); + } +} diff --git a/packages/album/feature-admin/src/lib/sheets/index.ts b/packages/album/feature-admin/src/lib/sheets/index.ts index a94565ba..d1f7bf4c 100644 --- a/packages/album/feature-admin/src/lib/sheets/index.ts +++ b/packages/album/feature-admin/src/lib/sheets/index.ts @@ -1 +1,2 @@ export * from './album-details/album-details.sheet'; +export * from './create-album/create-album.sheet';