Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ME]: Contacts for metadata #974

Merged
merged 7 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 1 addition & 0 deletions libs/common/fixtures/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export * from './lib/record-link.fixtures'
export * from './lib/records.fixtures'
export * from './lib/repository.fixtures'
export * from './lib/user.fixtures'
export * from './lib/individual.fixtures'
export * from './lib/user-feedbacks.fixtures'

export * from './lib/editor'
Expand Down
61 changes: 61 additions & 0 deletions libs/common/fixtures/src/lib/individual.fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Individual } from '@geonetwork-ui/common/domain/model/record'
import { barbieIncOrganizationFixture } from './organisations.fixture'

export const createIndividualFixture = (
overrides: Partial<Individual> = {}
): Individual => ({
firstName: 'Arnaud',
lastName: 'Demaison',
email: '[email protected]',
organization: barbieIncOrganizationFixture(),
role: 'point_of_contact',
...overrides,
})

export const barbieIndividualFixture = (): Individual =>
createIndividualFixture({
firstName: 'Barbara',
lastName: 'Roberts',
email: '[email protected]',
organization: barbieIncOrganizationFixture(),
role: 'point_of_contact',
})

export const someIndividualsFixture = (): Individual[] => [
barbieIndividualFixture(),
{
firstName: 'John',
lastName: 'Doe',
email: '[email protected]',
organization: barbieIncOrganizationFixture(),
role: 'owner',
},
{
firstName: 'Alice',
lastName: 'Smith',
email: '[email protected]',
organization: barbieIncOrganizationFixture(),
role: 'author',
},
{
firstName: 'Michael',
lastName: 'Johnson',
email: '[email protected]',
organization: barbieIncOrganizationFixture(),
role: 'contributor',
},
{
firstName: 'Emma',
lastName: 'Williams',
email: '[email protected]',
organization: barbieIncOrganizationFixture(),
role: 'rights_holder',
},
{
firstName: 'David',
lastName: 'Brown',
email: '[email protected]',
organization: barbieIncOrganizationFixture(),
role: 'stakeholder',
},
]
13 changes: 13 additions & 0 deletions libs/common/fixtures/src/lib/user.fixtures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,19 @@ export const barbieUserFixture = (): UserModel =>
'https://www.gravatar.com/avatar/dbdffd183622800bcf8587328daf43a6?d=mp',
})

export const johnDoeUserFixture = (): UserModel =>
createUserFixture({
id: '12345',
profile: 'User',
username: 'johndoe',
name: 'John',
surname: 'Doe',
email: '[email protected]',
organisation: 'Doe Enterprises',
profileIcon:
'https://www.gravatar.com/avatar/5f6d74eabcb57186a12f7c8ba40b4c9f?d=mp',
})

export const ghostUserFixture = (): UserModel =>
createUserFixture({
id: '161',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<div class="flex flex-col gap-3">
<gn-ui-autocomplete
[placeholder]="'Choose a contact'"
[action]="autoCompleteAction"
(itemSelected)="addContact($event)"
[displayWithFn]="displayWithFn"
[minCharacterCount]="1"
[clearOnSelection]="true"
>
</gn-ui-autocomplete>

<ng-container *ngIf="contacts.length > 0; else noContact">
<ng-container *ngIf="contacts.length === 1">
<ng-container *ngFor="let contact of contacts; let index = index">
<gn-ui-contact-card
[contact]="contact"
></gn-ui-contact-card> </ng-container
></ng-container>

<ng-container *ngIf="contacts.length > 1">
<gn-ui-sortable-list
[items]="contacts"
(itemsOrderChange)="handleContactsChanged($event)"
[elementTemplate]="contactTemplate"
></gn-ui-sortable-list>
<ng-template #contactTemplate let-contact>
<gn-ui-contact-card [contact]="contact"></gn-ui-contact-card>
</ng-template>
</ng-container>
</ng-container>
</div>

<ng-template #noContact>
<div
class="p-4 border border-primary bg-primary-lightest rounded-lg"
translate
>
editor.record.form.field.contacts.noContact
</div>
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { FormFieldContactsComponent } from './form-field-contacts.component'
import { ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'
import { PlatformServiceInterface } from '@geonetwork-ui/common/domain/platform.service.interface'
import { OrganizationsServiceInterface } from '@geonetwork-ui/common/domain/organizations.service.interface'
import { BehaviorSubject, of } from 'rxjs'
import {
Individual,
Organization,
} from '@geonetwork-ui/common/domain/model/record'
import { MockBuilder, MockInstance, MockProvider } from 'ng-mocks'
import { TranslateModule } from '@ngx-translate/core'
import {
barbieIncOrganizationFixture,
barbieUserFixture,
someIndividualsFixture,
someOrganizationsFixture,
someUsersFixture,
} from '@geonetwork-ui/common/fixtures'

describe('FormFieldContactsComponent', () => {
MockInstance.scope()

let component: FormFieldContactsComponent
let fixture: ComponentFixture<FormFieldContactsComponent>
let platformServiceInterface: PlatformServiceInterface
let organizationsServiceInterface: OrganizationsServiceInterface
let changeDetectorRef: ChangeDetectorRef

beforeEach(() => {
return MockBuilder(FormFieldContactsComponent)
})

const mockUsers = someUsersFixture()

beforeEach(() => {
TestBed.configureTestingModule({
imports: [FormFieldContactsComponent, TranslateModule.forRoot()],
providers: [
MockProvider(OrganizationsServiceInterface),
MockProvider(PlatformServiceInterface, {
getUsers: jest.fn().mockReturnValue(of(mockUsers)),
}),
MockProvider(ChangeDetectorRef, {
markForCheck: jest.fn().mockReturnValue({}),
}),
],
}).overrideComponent(FormFieldContactsComponent, {
set: {
changeDetection: ChangeDetectionStrategy.Default,
},
})

fixture = TestBed.createComponent(FormFieldContactsComponent)
component = fixture.componentInstance

changeDetectorRef = TestBed.inject(ChangeDetectorRef)
platformServiceInterface = TestBed.inject(PlatformServiceInterface)
organizationsServiceInterface = TestBed.inject(
OrganizationsServiceInterface
)

organizationsServiceInterface.organisations$ = new BehaviorSubject(
someOrganizationsFixture()
)

component.value = []

fixture.detectChanges()
})

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

describe('ngOnChanges', () => {
it('should initialize allOrganizations on first change', async () => {
const orgs: Organization[] = [{ name: 'Org1' }, { name: 'Org2' }]
organizationsServiceInterface.organisations$ = of(orgs)

component.value = []
await component.ngOnChanges({
value: {
currentValue: [],
previousValue: undefined,
firstChange: true,
isFirstChange: () => true,
},
})

expect(component.allOrganizations.size).toBe(2)
expect(component.allOrganizations.get('Org1')).toEqual({ name: 'Org1' })
expect(component.allOrganizations.get('Org2')).toEqual({ name: 'Org2' })
})

it('should update contacts and mark for check when value changes', async () => {
jest.spyOn(component, 'updateContacts')

component.value = []
await component.ngOnChanges({
value: {
currentValue: [],
previousValue: null,
firstChange: false,
isFirstChange: () => false,
},
})

expect(component.updateContacts).toHaveBeenCalled()
})
})

describe('updateContacts', () => {
beforeEach(async () => {
await component.ngOnChanges({
value: {
currentValue: [],
previousValue: undefined,
firstChange: true,
isFirstChange: () => true,
},
})
})

it('should update contacts with complete organization data', () => {
component.value = [
{
...someIndividualsFixture()[0],
organization: { name: barbieIncOrganizationFixture().name },
},
{
...someIndividualsFixture()[1],
organization: { name: barbieIncOrganizationFixture().name },
},
]

component.updateContacts()

expect(component.contacts.length).toBe(2)
expect(component.contacts[0].organization).toEqual(
barbieIncOrganizationFixture()
)
expect(component.contacts[1].organization).toEqual(
barbieIncOrganizationFixture()
)
})
})

describe('handleContactsChanged', () => {
it('should update contacts and emit valueChange', () => {
const contacts: Individual[] = someIndividualsFixture()
jest.spyOn(component.valueChange, 'emit')

component.handleContactsChanged(contacts)

expect(component.contacts).toEqual(contacts)
expect(component.valueChange.emit).toHaveBeenCalledWith(contacts)
})
})

describe('addContact', () => {
it('should add the contact and emit new contacts', () => {
const spy = jest.spyOn(component.valueChange, 'emit')
const mockUser = barbieUserFixture()
component.allOrganizations.set('Org1', { name: 'Org1' } as Organization)

component.addContact(mockUser)

expect(spy).toHaveBeenCalledWith([
{
address: '',
email: '[email protected]',
firstName: 'Barbara',
lastName: 'Roberts',
organization: { name: 'Barbie Inc.' } as Organization,
phone: '',
position: '',
role: 'point_of_contact',
},
])
})
})

describe('ngOnDestroy', () => {
it('should unsubscribe from subscriptions', () => {
jest.spyOn(component.subscription, 'unsubscribe')

component.ngOnDestroy()

expect(component.subscription.unsubscribe).toHaveBeenCalled()
})
})
})
Loading
Loading