diff --git a/src/app/features/home/pages/dashboard/dashboard.component.ts b/src/app/features/home/pages/dashboard/dashboard.component.ts index 989fc28a9..ab1603af8 100644 --- a/src/app/features/home/pages/dashboard/dashboard.component.ts +++ b/src/app/features/home/pages/dashboard/dashboard.component.ts @@ -7,7 +7,7 @@ import { Button } from 'primeng/button'; import { DialogService, DynamicDialogRef } from 'primeng/dynamicdialog'; import { TablePageEvent } from 'primeng/table'; -import { debounceTime, distinctUntilChanged } from 'rxjs'; +import { debounceTime, distinctUntilChanged, filter, tap } from 'rxjs'; import { Component, computed, DestroyRef, effect, inject, OnInit, signal } from '@angular/core'; import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop'; @@ -20,6 +20,7 @@ import { MY_PROJECTS_TABLE_PARAMS } from '@osf/shared/constants'; import { SortOrder } from '@osf/shared/enums'; import { IS_MEDIUM } from '@osf/shared/helpers'; import { MyResourcesItem, MyResourcesSearchFilters, TableParameters } from '@osf/shared/models'; +import { ProjectRedirectDialogService } from '@osf/shared/services'; import { ClearMyResources, GetMyProjects, MyResourcesSelectors } from '@osf/shared/stores'; @Component({ @@ -35,6 +36,7 @@ export class DashboardComponent implements OnInit { private readonly route = inject(ActivatedRoute); private readonly translateService = inject(TranslateService); private readonly dialogService = inject(DialogService); + private readonly projectRedirectDialogService = inject(ProjectRedirectDialogService); readonly isMedium = toSignal(inject(IS_MEDIUM)); @@ -175,13 +177,20 @@ export class DashboardComponent implements OnInit { createProject(): void { const dialogWidth = this.isMedium() ? '850px' : '95vw'; - this.dialogService.open(CreateProjectDialogComponent, { - width: dialogWidth, - focusOnShow: false, - header: this.translateService.instant('myProjects.header.createProject'), - closeOnEscape: true, - modal: true, - closable: true, - }); + this.dialogService + .open(CreateProjectDialogComponent, { + width: dialogWidth, + focusOnShow: false, + header: this.translateService.instant('myProjects.header.createProject'), + closeOnEscape: true, + modal: true, + closable: true, + }) + .onClose.pipe( + filter((result) => result.project.id), + tap((result) => this.projectRedirectDialogService.showProjectRedirectDialog(result.project.id)), + takeUntilDestroyed(this.destroyRef) + ) + .subscribe(); } } diff --git a/src/app/features/my-projects/components/create-project-dialog/create-project-dialog.component.ts b/src/app/features/my-projects/components/create-project-dialog/create-project-dialog.component.ts index 0e967d8f4..d9a1d4fa3 100644 --- a/src/app/features/my-projects/components/create-project-dialog/create-project-dialog.component.ts +++ b/src/app/features/my-projects/components/create-project-dialog/create-project-dialog.component.ts @@ -1,4 +1,4 @@ -import { createDispatchMap, select } from '@ngxs/store'; +import { createDispatchMap, select, Store } from '@ngxs/store'; import { TranslatePipe } from '@ngx-translate/core'; @@ -24,6 +24,7 @@ import { CreateProject, GetMyProjects, MyResourcesSelectors } from '@osf/shared/ }) export class CreateProjectDialogComponent { readonly dialogRef = inject(DynamicDialogRef); + private readonly store = inject(Store); private actions = createDispatchMap({ getMyProjects: GetMyProjects, @@ -70,8 +71,10 @@ export class CreateProjectDialogComponent { ) .subscribe({ next: () => { + const projects = this.store.selectSnapshot(MyResourcesSelectors.getProjects); + const newProject = projects[0]; this.actions.getMyProjects(1, MY_PROJECTS_TABLE_PARAMS.rows, {}); - this.dialogRef.close(); + this.dialogRef.close({ project: newProject }); }, }); } diff --git a/src/app/features/my-projects/my-projects.component.ts b/src/app/features/my-projects/my-projects.component.ts index 8c09683b5..df2eef8fe 100644 --- a/src/app/features/my-projects/my-projects.component.ts +++ b/src/app/features/my-projects/my-projects.component.ts @@ -7,7 +7,7 @@ import { DialogService } from 'primeng/dynamicdialog'; import { TablePageEvent } from 'primeng/table'; import { Tab, TabList, TabPanel, TabPanels, Tabs } from 'primeng/tabs'; -import { debounceTime, distinctUntilChanged } from 'rxjs'; +import { debounceTime, distinctUntilChanged, filter, tap } from 'rxjs'; import { ChangeDetectionStrategy, @@ -38,6 +38,7 @@ import { GetMyRegistrations, MyResourcesSelectors, } from '@osf/shared/stores'; +import { ProjectRedirectDialogService } from '@shared/services'; import { CreateProjectDialogComponent } from './components'; import { MY_PROJECTS_TABS } from './constants'; @@ -68,6 +69,7 @@ export class MyProjectsComponent implements OnInit { readonly router = inject(Router); readonly route = inject(ActivatedRoute); readonly translateService = inject(TranslateService); + readonly projectRedirectDialogService = inject(ProjectRedirectDialogService); readonly isLoading = signal(false); readonly isTablet = toSignal(inject(IS_MEDIUM)); @@ -326,14 +328,21 @@ export class MyProjectsComponent implements OnInit { createProject(): void { const dialogWidth = this.isTablet() ? '850px' : '95vw'; - this.dialogService.open(CreateProjectDialogComponent, { - width: dialogWidth, - focusOnShow: false, - header: this.translateService.instant('myProjects.header.createProject'), - closeOnEscape: true, - modal: true, - closable: true, - }); + this.dialogService + .open(CreateProjectDialogComponent, { + width: dialogWidth, + focusOnShow: false, + header: this.translateService.instant('myProjects.header.createProject'), + closeOnEscape: true, + modal: true, + closable: true, + }) + .onClose.pipe( + filter((result) => result.project.id), + tap((result) => this.projectRedirectDialogService.showProjectRedirectDialog(result.project.id)), + takeUntilDestroyed(this.destroyRef) + ) + .subscribe(); } navigateToProject(project: MyResourcesItem): void { diff --git a/src/app/shared/models/confirmation-options.model.ts b/src/app/shared/models/confirmation-options.model.ts index 8afbb57e5..03cb05c8f 100644 --- a/src/app/shared/models/confirmation-options.model.ts +++ b/src/app/shared/models/confirmation-options.model.ts @@ -18,6 +18,7 @@ export interface AcceptConfirmationOptions { // eslint-disable-next-line @typescript-eslint/no-explicit-any messageParams?: any; acceptLabelKey?: string; + rejectLabelKey?: string; onConfirm: () => void; onReject?: () => void; } diff --git a/src/app/shared/services/custom-confirmation.service.ts b/src/app/shared/services/custom-confirmation.service.ts index 51451e050..cd92fe5e3 100644 --- a/src/app/shared/services/custom-confirmation.service.ts +++ b/src/app/shared/services/custom-confirmation.service.ts @@ -43,7 +43,7 @@ export class CustomConfirmationService { label: this.translateService.instant(options.acceptLabelKey || 'common.buttons.move'), }, rejectButtonProps: { - label: this.translateService.instant('common.buttons.cancel'), + label: this.translateService.instant(options.rejectLabelKey || 'common.buttons.cancel'), severity: 'info', }, accept: () => { diff --git a/src/app/shared/services/index.ts b/src/app/shared/services/index.ts index 29694a143..66362a18d 100644 --- a/src/app/shared/services/index.ts +++ b/src/app/shared/services/index.ts @@ -15,6 +15,7 @@ export { LoaderService } from './loader.service'; export { MetaTagsService } from './meta-tags.service'; export { MyResourcesService } from './my-resources.service'; export { NodeLinksService } from './node-links.service'; +export { ProjectRedirectDialogService } from './project-redirect-dialog.service'; export { RegionsService } from './regions.service'; export { ResourceGuidService } from './resource.service'; export { ResourceCardService } from './resource-card.service'; diff --git a/src/app/shared/services/project-redirect-dialog.service.ts b/src/app/shared/services/project-redirect-dialog.service.ts new file mode 100644 index 000000000..f5d230b2d --- /dev/null +++ b/src/app/shared/services/project-redirect-dialog.service.ts @@ -0,0 +1,23 @@ +import { inject, Injectable } from '@angular/core'; +import { Router } from '@angular/router'; + +import { CustomConfirmationService } from './custom-confirmation.service'; + +@Injectable({ + providedIn: 'root', +}) +export class ProjectRedirectDialogService { + private readonly confirmationService = inject(CustomConfirmationService); + private readonly router = inject(Router); + + showProjectRedirectDialog(projectId: string): void { + this.confirmationService.confirmAccept({ + headerKey: 'myProjects.redirectDialog.header', + messageKey: 'myProjects.redirectDialog.message', + acceptLabelKey: 'myProjects.redirectDialog.confirmButton', + rejectLabelKey: 'myProjects.redirectDialog.rejectButton', + onConfirm: () => this.router.navigate(['/', projectId]), + onReject: () => null, + }); + } +} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index f7d818057..fba1bd785 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -437,6 +437,12 @@ }, "updateProjectDetailsMessage": "Successfully updated project details.", "updateProjectSettingsMessage": "Successfully updated project settings." + }, + "redirectDialog": { + "header": "Success", + "message": "New project created successfully!", + "confirmButton": "Go to project", + "rejectButton": "Keep working here" } }, "myProfile": {