Skip to content

Commit a10bbcc

Browse files
committed
SF-3772 Prevent duplicate onboarding requests
1 parent f3bdae9 commit a10bbcc

5 files changed

Lines changed: 37 additions & 14 deletions

File tree

src/SIL.XForge.Scripture/ClientApp/src/app/serval-administration/onboarding-request-detail/onboarding-request-detail.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,8 @@ import { NoticeComponent } from '../../shared/notice/notice.component';
3434
import { projectLabel } from '../../shared/utils';
3535
import { normalizeLanguageCodeToISO639_3 } from '../../translate/draft-generation/draft-utils';
3636
import {
37-
DraftingSignupFormData,
3837
OnboardingRequest,
38+
OnboardingRequestFormData,
3939
OnboardingRequestResolutionKey,
4040
OnboardingRequestResolutionMetadata,
4141
OnboardingRequestService
@@ -236,7 +236,7 @@ export class OnboardingRequestDetailComponent extends DataLoadingComponent imple
236236

237237
getStatus = this.onboardingRequestService.getStatus;
238238

239-
get formData(): DraftingSignupFormData {
239+
get formData(): OnboardingRequestFormData {
240240
return this.request!.submission.formData;
241241
}
242242

src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-generation.component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ export class DraftGenerationComponent extends DataLoadingComponent implements On
174174
protected readonly i18n: I18nService,
175175
private readonly onlineStatusService: OnlineStatusService,
176176
private readonly preTranslationSignupUrlService: PreTranslationSignupUrlService,
177-
private readonly draftingSignupService: OnboardingRequestService,
177+
private readonly onboardingRequestService: OnboardingRequestService,
178178
protected readonly noticeService: NoticeService,
179179
protected readonly urlService: ExternalUrlService,
180180
protected readonly featureFlags: FeatureFlagService,
@@ -290,7 +290,7 @@ export class DraftGenerationComponent extends DataLoadingComponent implements On
290290
// Check if user has already submitted a signup for this project
291291
if (this.activatedProject.projectId != null) {
292292
try {
293-
this.onboardingRequest = await this.draftingSignupService.getOpenOnboardingRequest(
293+
this.onboardingRequest = await this.onboardingRequestService.getOpenOnboardingRequest(
294294
this.activatedProject.projectId
295295
);
296296
} catch {

src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/draft-signup-form/draft-onboarding-form.component.ts

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { User } from 'realtime-server/lib/esm/common/models/user';
1616
import { DevOnlyComponent } from 'src/app/shared/dev-only/dev-only.component';
1717
import { ActivatedProjectService } from 'xforge-common/activated-project.service';
1818
import { DataLoadingComponent } from 'xforge-common/data-loading-component';
19+
import { DialogService } from 'xforge-common/dialog.service';
1920
import { I18nService } from 'xforge-common/i18n.service';
2021
import { NoticeService } from 'xforge-common/notice.service';
2122
import { UserService } from 'xforge-common/user.service';
@@ -27,7 +28,7 @@ import { ProjectSelectComponent } from '../../../project-select/project-select.c
2728
import { BookMultiSelectComponent } from '../../../shared/book-multi-select/book-multi-select.component';
2829
import { JsonViewerComponent } from '../../../shared/json-viewer/json-viewer.component';
2930
import { compareProjectsForSorting, projectLabel } from '../../../shared/utils';
30-
import { DraftingSignupFormData, OnboardingRequestService } from '../onboarding-request.service';
31+
import { OnboardingRequestFormData, OnboardingRequestService } from '../onboarding-request.service';
3132

3233
export const DRAFT_SIGNUP_RESPONSE_DAYS = { min: 1, max: 3 } as const;
3334

@@ -133,8 +134,9 @@ export class DraftOnboardingFormComponent extends DataLoadingComponent implement
133134
private readonly activatedProject: ActivatedProjectService,
134135
private readonly userService: UserService,
135136
private readonly paratextService: ParatextService,
136-
private readonly draftingSignupService: OnboardingRequestService,
137+
private readonly onboardingRequestService: OnboardingRequestService,
137138
protected readonly noticeService: NoticeService,
139+
protected readonly dialogService: DialogService,
138140
private readonly destroyRef: DestroyRef,
139141
private readonly cd: ChangeDetectorRef,
140142
private readonly i18n: I18nService
@@ -207,18 +209,18 @@ export class DraftOnboardingFormComponent extends DataLoadingComponent implement
207209

208210
async onSubmit(): Promise<void> {
209211
const projectId = this.activatedProject.projectId;
210-
if (projectId == null || this.uiState === 'submitting') {
211-
return;
212-
}
212+
if (projectId == null || this.uiState === 'submitting') return;
213+
214+
if (await this.checkAndWarnIfAlreadySubmitted()) return;
213215

214216
if (this.signupForm.valid === true) {
215217
this.uiState = 'submitting';
216218
this.cd.markForCheck();
217219

218-
const formData: DraftingSignupFormData = this.signupForm.getRawValue() as DraftingSignupFormData;
220+
const formData = this.signupForm.getRawValue() as OnboardingRequestFormData;
219221

220222
try {
221-
const requestId = await this.draftingSignupService.submitOnboardingRequest(projectId, formData);
223+
const requestId = await this.onboardingRequestService.submitOnboardingRequest(projectId, formData);
222224

223225
// For testing purposes, store and display the submitted data
224226
this.submittedData = { requestId, projectId, formData };
@@ -313,6 +315,26 @@ export class DraftOnboardingFormComponent extends DataLoadingComponent implement
313315
}
314316
}
315317

318+
/**
319+
* If a request has already been submitted:
320+
* - Informs user with a message dialog
321+
* - Redirects to drafting page when user closes dialog
322+
* - Resolves to true
323+
*
324+
* Otherwise, resolves to false
325+
*/
326+
private async checkAndWarnIfAlreadySubmitted(): Promise<boolean> {
327+
if (this.activatedProject.projectId == null) return false;
328+
329+
if ((await this.onboardingRequestService.getOpenOnboardingRequest(this.activatedProject.projectId)) == null) {
330+
return false;
331+
} else {
332+
await this.dialogService.message('draft_sources.request_already_submitted', undefined, true);
333+
this.cancel();
334+
return true;
335+
}
336+
}
337+
316338
private async loadProjectsAndResources(): Promise<void> {
317339
try {
318340
const [projects, resources] = await Promise.all([

src/SIL.XForge.Scripture/ClientApp/src/app/translate/draft-generation/onboarding-request.service.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export interface OnboardingRequestComment {
1010
dateCreated: string;
1111
}
1212

13-
export interface DraftingSignupFormData {
13+
export interface OnboardingRequestFormData {
1414
name: string;
1515
email: string;
1616
organization: string;
@@ -43,7 +43,7 @@ export interface OnboardingRequest {
4343
projectId: string;
4444
userId: string;
4545
timestamp: string;
46-
formData: DraftingSignupFormData;
46+
formData: OnboardingRequestFormData;
4747
};
4848
assigneeId: string;
4949
status: OnboardingRequestStatusOption;
@@ -104,7 +104,7 @@ export class OnboardingRequestService {
104104
}
105105

106106
/** Submits a new signup request. */
107-
async submitOnboardingRequest(projectId: string, formData: DraftingSignupFormData): Promise<string> {
107+
async submitOnboardingRequest(projectId: string, formData: OnboardingRequestFormData): Promise<string> {
108108
return (await this.onlineInvoke<string>('submitOnboardingRequest', { projectId, formData }))!;
109109
}
110110

src/SIL.XForge.Scripture/ClientApp/src/assets/i18n/non_checking_en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,7 @@
403403
"select_project_to_translate": "Select the project to translate.",
404404
"some_projects_use_back_translation": "Some projects get better results by adding a back translation as another reference.",
405405
"source_side_language_codes_differ": "All source and reference projects must be in the same language. Please select different source or reference projects.",
406+
"request_already_submitted": "A request to activate drafting on this project has already been submitted. Please wait for a response from the team.",
406407
"state_connecting": "Connecting",
407408
"state_sync_failed": "There was an error syncing",
408409
"state_sync_successful": "Sync successful",

0 commit comments

Comments
 (0)