diff --git a/front-end/src/app/tabs/organizations/organization.page.html b/front-end/src/app/tabs/organizations/organization.page.html
new file mode 100644
index 0000000..fb9b3b9
--- /dev/null
+++ b/front-end/src/app/tabs/organizations/organization.page.html
@@ -0,0 +1,36 @@
+
+
+ {{ 'ORGANIZATIONS.DETAILS' | translate }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ 'ORGANIZATIONS.SPEAKERS' | translate }}
+
+
+
+
+
+
+
+
+ {{ 'COMMON.NO_ELEMENT_FOUND' | translate }}
+
+
+
+
+
+
+
+
+
+
diff --git a/front-end/src/app/tabs/organizations/organization.page.scss b/front-end/src/app/tabs/organizations/organization.page.scss
new file mode 100644
index 0000000..e69de29
diff --git a/front-end/src/app/tabs/organizations/organization.page.ts b/front-end/src/app/tabs/organizations/organization.page.ts
new file mode 100644
index 0000000..8431caf
--- /dev/null
+++ b/front-end/src/app/tabs/organizations/organization.page.ts
@@ -0,0 +1,51 @@
+import { Component, OnInit } from '@angular/core';
+import { ActivatedRoute } from '@angular/router';
+
+import { IDEALoadingService, IDEAMessageService } from '@idea-ionic/common';
+
+import { AppService } from 'src/app/app.service';
+import { OrganizationsService } from './organizations.service';
+import { SpeakersService } from '../speakers/speakers.service';
+
+import { Speaker } from '@models/speaker.model';
+import { Organization } from '@models/organization.model';
+
+@Component({
+ selector: 'app-organization',
+ templateUrl: './organization.page.html',
+ styleUrls: ['./organization.page.scss']
+})
+export class OrganizationPage implements OnInit {
+ organization: Organization;
+ speakers: Speaker[];
+
+ constructor(
+ private route: ActivatedRoute,
+ private loading: IDEALoadingService,
+ private message: IDEAMessageService,
+ private _organizations: OrganizationsService,
+ private _speakers: SpeakersService,
+ public app: AppService
+ ) {}
+
+ async ngOnInit() {
+ await this.loadData();
+ }
+
+ async loadData() {
+ try {
+ await this.loading.show();
+ const organizationId = this.route.snapshot.paramMap.get('organizationId');
+ this.organization = await this._organizations.getById(organizationId);
+ this.speakers = await this._speakers.getList({ organization: this.organization.organizationId, force: true });
+ } catch (err) {
+ this.message.error('COMMON.NOT_FOUND');
+ } finally {
+ await this.loading.hide();
+ }
+ }
+
+ async filterSpeakers(search: string = ''): Promise {
+ this.speakers = await this._speakers.getList({ search, organization: this.organization.organizationId });
+ }
+}
diff --git a/front-end/src/app/tabs/organizations/organizationCard.component.ts b/front-end/src/app/tabs/organizations/organizationCard.component.ts
new file mode 100644
index 0000000..6e1603a
--- /dev/null
+++ b/front-end/src/app/tabs/organizations/organizationCard.component.ts
@@ -0,0 +1,59 @@
+import { Component, Input } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { IonicModule } from '@ionic/angular';
+
+import { IDEATranslationsModule } from '@idea-ionic/common';
+
+import { AppService } from 'src/app/app.service';
+
+import { Organization } from '@models/organization.model';
+
+@Component({
+ standalone: true,
+ imports: [CommonModule, FormsModule, IonicModule, IDEATranslationsModule],
+ selector: 'app-organization-card',
+ template: `
+
+
+
+ {{ organization.name }}
+
+ {{ organization.website }}
+
+
+ {{ organization.contactEmail }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `
+})
+export class OrganizationCardStandaloneComponent {
+ @Input() organization: Organization;
+ @Input() preview: boolean;
+
+ constructor(public app: AppService) {}
+}
diff --git a/front-end/src/app/tabs/organizations/organizations-routing.module.ts b/front-end/src/app/tabs/organizations/organizations-routing.module.ts
new file mode 100644
index 0000000..e82c7b6
--- /dev/null
+++ b/front-end/src/app/tabs/organizations/organizations-routing.module.ts
@@ -0,0 +1,16 @@
+import { NgModule } from '@angular/core';
+import { Routes, RouterModule } from '@angular/router';
+
+import { OrganizationsPage } from './organizations.page';
+import { OrganizationPage } from './organization.page';
+
+const routes: Routes = [
+ { path: '', component: OrganizationsPage },
+ { path: ':organizationId', component: OrganizationPage }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class OrganizationsRoutingModule {}
diff --git a/front-end/src/app/tabs/organizations/organizations.module.ts b/front-end/src/app/tabs/organizations/organizations.module.ts
new file mode 100644
index 0000000..635d747
--- /dev/null
+++ b/front-end/src/app/tabs/organizations/organizations.module.ts
@@ -0,0 +1,25 @@
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { IonicModule } from '@ionic/angular';
+import { FormsModule } from '@angular/forms';
+import { IDEATranslationsModule } from '@idea-ionic/common';
+
+import { OrganizationsRoutingModule } from './organizations-routing.module';
+import { OrganizationPage } from './organization.page';
+import { OrganizationsPage } from './organizations.page';
+import { OrganizationCardStandaloneComponent } from './organizationCard.component';
+import { SpeakerCardStandaloneComponent } from '../speakers/speakerCard.component';
+
+@NgModule({
+ imports: [
+ CommonModule,
+ FormsModule,
+ IonicModule,
+ IDEATranslationsModule,
+ OrganizationsRoutingModule,
+ OrganizationCardStandaloneComponent,
+ SpeakerCardStandaloneComponent
+ ],
+ declarations: [OrganizationsPage, OrganizationPage]
+})
+export class OrganizationsModule {}
diff --git a/front-end/src/app/tabs/organizations/organizations.page.html b/front-end/src/app/tabs/organizations/organizations.page.html
new file mode 100644
index 0000000..a23af6b
--- /dev/null
+++ b/front-end/src/app/tabs/organizations/organizations.page.html
@@ -0,0 +1,27 @@
+
+
+
+ {{ 'ORGANIZATIONS.LIST' | translate }}
+
+
+
+
+
+
+
+ {{ 'COMMON.NO_ELEMENT_FOUND' | translate }}
+
+
+
+
+
+ {{ organization.name }}
+
+
+
\ No newline at end of file
diff --git a/front-end/src/app/tabs/organizations/organizations.page.scss b/front-end/src/app/tabs/organizations/organizations.page.scss
new file mode 100644
index 0000000..e69de29
diff --git a/front-end/src/app/tabs/organizations/organizations.page.ts b/front-end/src/app/tabs/organizations/organizations.page.ts
new file mode 100644
index 0000000..e99d4b0
--- /dev/null
+++ b/front-end/src/app/tabs/organizations/organizations.page.ts
@@ -0,0 +1,49 @@
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { IonContent } from '@ionic/angular';
+
+import { Organization } from '@models/organization.model';
+import { OrganizationsService } from './organizations.service';
+import { AppService } from 'src/app/app.service';
+import { IDEALoadingService, IDEAMessageService } from '@idea-ionic/common';
+
+@Component({
+ selector: 'app-organizations',
+ templateUrl: './organizations.page.html',
+ styleUrls: ['./organizations.page.scss']
+})
+export class OrganizationsPage implements OnInit {
+ @ViewChild(IonContent) content: IonContent;
+
+ organizations: Organization[];
+ filteredOrganizations: Organization[];
+
+ constructor(
+ private loading: IDEALoadingService,
+ private message: IDEAMessageService,
+ private _organizations: OrganizationsService,
+ public app: AppService
+ ) {}
+
+ ngOnInit() {
+ this.loadData();
+ }
+
+ async loadData() {
+ try {
+ await this.loading.show();
+ this.organizations = await this._organizations.getList({});
+ } catch (error) {
+ this.message.error('COMMON.OPERATION_FAILED');
+ } finally {
+ this.loading.hide();
+ }
+ }
+
+ async filterOrganizations(search = ''): Promise {
+ this.organizations = await this._organizations.getList({ search });
+ }
+
+ selectOrganization(organization: Organization) {
+ this.app.goToInTabs(['organizations', organization.organizationId]);
+ }
+}
\ No newline at end of file
diff --git a/front-end/src/app/tabs/speakers/speakerCard.component.ts b/front-end/src/app/tabs/speakers/speakerCard.component.ts
new file mode 100644
index 0000000..ccda662
--- /dev/null
+++ b/front-end/src/app/tabs/speakers/speakerCard.component.ts
@@ -0,0 +1,65 @@
+import { Component, Input } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { FormsModule } from '@angular/forms';
+import { IonicModule } from '@ionic/angular';
+
+import { IDEATranslationsModule } from '@idea-ionic/common';
+
+import { AppService } from 'src/app/app.service';
+
+import { Speaker } from '@models/speaker.model';
+
+@Component({
+ standalone: true,
+ imports: [CommonModule, FormsModule, IonicModule, IDEATranslationsModule],
+ selector: 'app-speaker-card',
+ template: `
+
+
+
+ {{ speaker.name }}
+ {{ speaker.description }}
+
+
+
+
+
+
+
+ {{ speaker.name }}
+ {{ speaker.organization }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ `
+})
+export class SpeakerCardStandaloneComponent {
+ @Input() speaker: Speaker;
+ @Input() preview: boolean;
+
+ constructor(public app: AppService) {}
+}
\ No newline at end of file
diff --git a/front-end/src/app/tabs/speakers/speakers.service.ts b/front-end/src/app/tabs/speakers/speakers.service.ts
index 97f9d59..e638a9e 100644
--- a/front-end/src/app/tabs/speakers/speakers.service.ts
+++ b/front-end/src/app/tabs/speakers/speakers.service.ts
@@ -14,22 +14,24 @@ export class SpeakersService {
constructor(private api: IDEAApiService) {}
- private async loadList(): Promise {
- this.speakers = (await this.api.getResource(['speakers'])).map(s => new Speaker(s));
+ private async loadList(organization?: string): Promise {
+ this.speakers = (await this.api.getResource(['speakers'], { params: { organization } })).map(s => new Speaker(s));
}
/**
* Get (and optionally filter) the list of speakers.
* Note: it can be paginated.
* Note: it's a slice of the array.
+ * Note: if organization id is passed, it will filter speakers for that organization.
*/
async getList(options: {
force?: boolean;
withPagination?: boolean;
startPaginationAfterId?: string;
search?: string;
+ organization?: string;
}): Promise {
- if (!this.speakers || options.force) await this.loadList();
+ if (!this.speakers || options.force) await this.loadList(options.organization);
if (!this.speakers) return null;
options.search = options.search ? String(options.search).toLowerCase() : '';
diff --git a/front-end/src/app/tabs/tabs.routing.module.ts b/front-end/src/app/tabs/tabs.routing.module.ts
index 72d5fe5..55df25e 100644
--- a/front-end/src/app/tabs/tabs.routing.module.ts
+++ b/front-end/src/app/tabs/tabs.routing.module.ts
@@ -24,6 +24,10 @@ const routes: Routes = [
{
path: 'rooms',
loadChildren: (): Promise => import('./rooms/rooms.module').then(m => m.RoomsModule)
+ },
+ {
+ path: 'organizations',
+ loadChildren: (): Promise => import('./organizations/organizations.module').then(m => m.OrganizationsModule)
}
]
}
diff --git a/front-end/src/assets/i18n/en.json b/front-end/src/assets/i18n/en.json
index ed45be5..636ed74 100644
--- a/front-end/src/assets/i18n/en.json
+++ b/front-end/src/assets/i18n/en.json
@@ -337,5 +337,10 @@
"ROOMS": {
"DETAILS": "Room details",
"SESSIONS": "Sessions hosted in this room"
+ },
+ "ORGANIZATIONS": {
+ "LIST": "Organizations list",
+ "DETAILS": "Organization details",
+ "SPEAKERS": "Speakers from this organization"
}
}