Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
18d44e7
refactor(preprints-state): Renamed Preprints -> PreprintProviders
rrromchIk Jul 3, 2025
31bc13f
Merge branch 'main' into feat/submit-preprint
rrromchIk Jul 3, 2025
187896c
refactor(preprints-services): Renamed services to have 'preprints' pr…
rrromchIk Jul 3, 2025
0665024
fix(json-api-post): Fixed errors during to merge conflict
rrromchIk Jul 3, 2025
13e082d
refactor(preprints-state): Renamed Preprints -> PreprintProviders
rrromchIk Jul 3, 2025
a55bd93
refactor(preprints-models): Decomposed, used shared models. Moved som…
rrromchIk Jul 3, 2025
cf8cd63
refactor(router): Moved preprint routes to root folder of feature
rrromchIk Jul 3, 2025
c27d8da
refactor(preprints-components): Rename and reorganize component files…
rrromchIk Jul 3, 2025
f6bfb32
fix(preprints-models): Removed unused model
rrromchIk Jul 3, 2025
189d6cb
refactor(license): Made license more reusable by removing card wrapper
rrromchIk Jul 3, 2025
fe5e33e
refactor(metadata-license): Removed redundant wrapper
rrromchIk Jul 3, 2025
04d15f2
fix(comments): Fixed comments
rrromchIk Jul 3, 2025
ec9c9fb
feat(author-assertions): Partly implemented step with missing availab…
rrromchIk Jul 3, 2025
14051fe
refactor(validators): Moved linkValidator from helper function to sha…
rrromchIk Jul 3, 2025
ddd89b2
feat(array-input): Implemented reusable component for array input
rrromchIk Jul 3, 2025
d547779
feat(array-input): Used array-input for data links and prereg links
rrromchIk Jul 3, 2025
97e73e9
Merge branch 'main' into feat/submit-preprint
rrromchIk Jul 3, 2025
1ad7a34
Merge branch 'main' into feat/submit-preprint
rrromchIk Jul 4, 2025
83a6b8e
refactor(author-assertions): Refactored step. Fixed minor issues
rrromchIk Jul 4, 2025
26e4f44
fix(translations): Update URL validation message for clarity
rrromchIk Jul 4, 2025
3959764
fix(comments): Fixed comments
rrromchIk Jul 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/app/core/helpers/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
export * from './http.helper';
export * from './i18n.helper';
export * from './link-validator.helper';
export * from './types.helper';
16 changes: 0 additions & 16 deletions src/app/core/helpers/link-validator.helper.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<section>
<div class="flex flex-column gap-3">
@let formArrayControls = formArray().controls;
@for (control of formArrayControls; track $index) {
<div class="flex flex-row gap-2 align-items-center">
<osf-text-input class="w-full" [control]="control" [placeholder]="inputPlaceholder()" [maxLength]="255" />
@if (formArrayControls.length > 1) {
<p-button class="danger-icon-btn" icon="fas fa-trash" severity="danger" text (click)="remove($index)" />
}
</div>
}
</div>

<section class="m-t-24 flex flex-row justify-content-end">
<p-button label="Add One More" severity="secondary" (click)="add()" />
</section>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { ArrayInputComponent } from './array-input.component';

describe('ArrayInputComponent', () => {
let component: ArrayInputComponent;
let fixture: ComponentFixture<ArrayInputComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ArrayInputComponent],
}).compileComponents();

fixture = TestBed.createComponent(ArrayInputComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Button } from 'primeng/button';

import { ChangeDetectionStrategy, Component, input } from '@angular/core';
import { FormArray, FormControl, ReactiveFormsModule, ValidatorFn } from '@angular/forms';

import { TextInputComponent } from '@shared/components';

@Component({
selector: 'osf-array-input',
imports: [ReactiveFormsModule, Button, TextInputComponent],
templateUrl: './array-input.component.html',
styleUrl: './array-input.component.scss',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ArrayInputComponent {
formArray = input.required<FormArray<FormControl>>();
inputPlaceholder = input.required<string>();
validators = input.required<ValidatorFn[]>();

add() {
this.formArray().push(
new FormControl('', {
nonNullable: true,
validators: this.validators(),
})
);
}

remove(index: number) {
if (this.formArray().length > 1) {
this.formArray().removeAt(index);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,238 @@
<h2>Author Assertions</h2>

<p-card styleClass="m-t-24" class="card">
<div>
<h2>Conflict of Interest</h2>

<p class="m-t-12">
The Conflict of Interest (COI) assertion is made on behalf of all the authors listed for this preprint. COIs
include: financial involvement in any entity such as honoraria, grants, speaking fees, employment, consultancies,
stock ownership, expert testimony, and patents or licenses. COIs can also include non-financial interests such as
personal or professional relationships or pre-existing beliefs in the subject matter or materials discussed in
this preprint.
</p>

<div class="m-t-24 flex flex-row gap-4">
<div class="flex flex-row gap-2">
<p-radio-button
inputId="coi-yes"
name="coi"
[value]="true"
[formControl]="authorAssertionsForm.controls['hasCoi']"
/>
<label for="coi-yes">Yes</label>
</div>

<div class="flex flex-row gap-2">
<p-radio-button
inputId="coi-no"
name="coi"
[value]="false"
[formControl]="authorAssertionsForm.controls['hasCoi']"
/>
<label for="coi-no">No</label>
</div>
</div>

<textarea
class="m-t-24 w-full"
[ngClass]="{ 'cursor-not-allowed': !authorAssertionsForm.value.hasCoi }"
pTextarea
id="coi-reason"
[rows]="3"
[formControl]="authorAssertionsForm.controls['coiStatement']"
[placeholder]="
authorAssertionsForm.value.hasCoi
? 'Describe'
: 'Author asserted there is no Conflict of Interest with this preprint.'
"
></textarea>
@let coiStatementControl = authorAssertionsForm.controls['coiStatement'];
@if (coiStatementControl.errors?.['required'] && (coiStatementControl.touched || coiStatementControl.dirty)) {
<p-message class="simple-variant flex mt-1" severity="error" variant="simple" size="small">
{{ INPUT_VALIDATION_MESSAGES.required | translate }}
</p-message>
}
</div>
</p-card>

<p-card styleClass="m-t-24" class="card">
<div>
<h2>Public Data</h2>

<p class="m-t-12">
Data refers to raw and/or processed information (quantitative or qualitative) used for the analyses, case studies,
and/or descriptive interpretation in the preprint. Public data could include data posted to open-access
repositories, public archival library collection, or government archive. For data that is available under limited
circumstances (e.g., after signing a data sharing agreement), choose the ‘No’ option and use the comment box to
explain how others could access the data.
</p>

<div class="m-t-24 flex flex-row gap-4">
<div class="flex flex-row gap-2">
<p-radio-button
inputId="publicDataAvailable"
name="publicData"
[value]="ApplicabilityStatus.Applicable"
[formControl]="authorAssertionsForm.controls['hasDataLinks']"
/>
<label for="publicDataAvailable">Available</label>
</div>

<div class="flex flex-row gap-2">
<p-radio-button
inputId="publicDataUnavailable"
name="publicData"
[value]="ApplicabilityStatus.Unavailable"
[formControl]="authorAssertionsForm.controls['hasDataLinks']"
/>
<label for="publicDataUnavailable">No</label>
</div>

<div class="flex flex-row gap-2">
<p-radio-button
inputId="publicDataNotApplicable"
name="publicData"
[value]="ApplicabilityStatus.NotApplicable"
[formControl]="authorAssertionsForm.controls['hasDataLinks']"
/>
<label for="publicDataNotApplicable">Not Applicable</label>
</div>
</div>

@let hasDataLinks = authorAssertionsForm.value.hasDataLinks!;
@if (hasDataLinks === ApplicabilityStatus.Unavailable || hasDataLinks === ApplicabilityStatus.NotApplicable) {
<textarea
class="m-t-24 w-full"
[ngClass]="{
'cursor-not-allowed': hasDataLinks === ApplicabilityStatus.NotApplicable,
}"
pTextarea
id="public-data-description"
[formControl]="authorAssertionsForm.controls['whyNoData']"
[rows]="3"
[placeholder]="
hasDataLinks === ApplicabilityStatus.Unavailable
? 'Describe'
: 'Author asserted there is no data associated with this preprint.'
"
></textarea>
@let whyNoDataControl = authorAssertionsForm.controls['whyNoData'];
@if (whyNoDataControl.errors?.['required'] && (whyNoDataControl.touched || whyNoDataControl.dirty)) {
<p-message class="simple-variant flex mt-1" severity="error" variant="simple" size="small">
{{ INPUT_VALIDATION_MESSAGES.required | translate }}
</p-message>
}
} @else {
<div class="m-t-24">
<osf-array-input
[formArray]="authorAssertionsForm.controls['dataLinks']"
inputPlaceholder="Link to data"
[validators]="linkValidators"
/>
</div>
}
</div>
</p-card>

<p-card styleClass="m-t-24" class="card">
<div>
<h2>Public Preregistration</h2>

<p class="m-t-12">
A preregistration is a description of the research design and/or analysis plan that is created and registered
before researchers collected data or before they have seen/interacted with preexisting data. The description
should appear in a public registry (e.g., clinicaltrials.gov, OSF, AEA registry).
</p>
</div>

<div class="m-t-24 flex flex-row gap-4">
<div class="flex flex-row gap-2">
<p-radio-button
inputId="preregistrationAvailable"
name="publicPreregistration"
[value]="ApplicabilityStatus.Applicable"
[formControl]="authorAssertionsForm.controls['hasPreregLinks']"
/>
<label for="preregistrationAvailable">Available</label>
</div>

<div class="flex flex-row gap-2">
<p-radio-button
inputId="preregistrationUnavailable"
name="publicPreregistration"
[value]="ApplicabilityStatus.Unavailable"
[formControl]="authorAssertionsForm.controls['hasPreregLinks']"
/>
<label for="preregistrationUnavailable">No</label>
</div>

<div class="flex flex-row gap-2">
<p-radio-button
inputId="preregistrationNotApplicable"
name="publicPreregistration"
[value]="ApplicabilityStatus.NotApplicable"
[formControl]="authorAssertionsForm.controls['hasPreregLinks']"
/>
<label for="preregistrationNotApplicable">Not Applicable</label>
</div>
</div>
@let hasPreregLinks = authorAssertionsForm.value.hasPreregLinks!;
@if (hasPreregLinks === ApplicabilityStatus.Unavailable || hasPreregLinks === ApplicabilityStatus.NotApplicable) {
<textarea
class="m-t-24 w-full"
[ngClass]="{
'cursor-not-allowed': hasPreregLinks === ApplicabilityStatus.NotApplicable,
}"
pTextarea
id="public-data-description"
[rows]="3"
[formControl]="authorAssertionsForm.controls['whyNoPrereg']"
[placeholder]="
hasPreregLinks === ApplicabilityStatus.Unavailable
? 'Describe'
: 'The author asserts that a preregistration is not applicable because no data collection, extraction, or analysis is reported in the preprint.'
"
></textarea>
@let hasPreregLinksControl = authorAssertionsForm.controls['hasPreregLinks'];
@if (hasPreregLinksControl.errors?.['required'] && (hasPreregLinksControl.touched || hasPreregLinksControl.dirty)) {
<p-message class="simple-variant flex mt-1" severity="error" variant="simple" size="small">
{{ INPUT_VALIDATION_MESSAGES.required | translate }}
</p-message>
}
} @else {
<p-select
id="links-info"
class="w-12 md:w-6"
styleClass="m-t-24"
placeholder="Choose one"
[formControl]="authorAssertionsForm.controls['preregLinkInfo']"
[options]="preregLinkOptions"
optionLabel="label"
optionValue="value"
[showClear]="false"
/>

<div class="m-t-24">
<osf-array-input
[formArray]="authorAssertionsForm.controls['preregLinks']"
inputPlaceholder="Link to data"
[validators]="linkValidators"
/>
</div>
}
</p-card>

<section class="m-t-48 flex flex-row justify-content-end align-items-center gap-2">
<p-button class="w-6 md:w-6rem" styleClass="w-full" label="Back" severity="info" />
<p-button
class="w-6 md:w-9rem"
styleClass="w-full"
label="Next"
[pTooltip]="authorAssertionsForm.invalid ? 'Fill in \'Required\' fields to continue' : ''"
tooltipPosition="top"
[disabled]="authorAssertionsForm.invalid"
[loading]="isUpdatingPreprint()"
(click)="nextButtonClicked()"
/>
</section>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
@use "assets/styles/variables" as var;

.card {
@media (max-width: var.$breakpoint-sm) {
--p-card-body-padding: 0.75rem;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';

import { AuthorAssertionsStepComponent } from './author-assertions-step.component';

describe('AuthorAssertionsComponent', () => {
let component: AuthorAssertionsStepComponent;
let fixture: ComponentFixture<AuthorAssertionsStepComponent>;

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [AuthorAssertionsStepComponent],
}).compileComponents();

fixture = TestBed.createComponent(AuthorAssertionsStepComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should create', () => {
expect(component).toBeTruthy();
});
});
Loading