From 0e152aee7772a5df11208219b0e82e39a72efc90 Mon Sep 17 00:00:00 2001 From: DavidMockler Date: Fri, 26 Jul 2024 16:20:17 +0100 Subject: [PATCH] Prototyping potential Digital Reader Library layouts --- api/src/endpoint/drStory/ownerId.ts | 8 +- api/src/endpoint/drStory/public.ts | 21 ++ api/src/endpoint/drStory/verified.ts | 47 ++++ api/src/routes/drStory.route.ts | 14 +- .../src/app/core/services/dr-story.service.ts | 29 +++ .../digital-reader-library.component.html | 78 +++++- .../digital-reader-library.component.scss | 9 +- .../digital-reader-library.component.ts | 22 +- .../dr-story-drawer.component.html | 53 ++++ .../dr-story-drawer.component.scss | 104 ++++++++ .../dr-story-drawer.component.spec.ts | 27 ++ .../dr-story-drawer.component.ts | 243 ++++++++++++++++++ ngapp/src/app/nav-bar/nav-bar.module.ts | 14 +- ngapp/src/app/student/student.module.ts | 3 + ngapp/src/app/translation.ts | 6 + 15 files changed, 653 insertions(+), 25 deletions(-) create mode 100644 api/src/endpoint/drStory/public.ts create mode 100644 api/src/endpoint/drStory/verified.ts create mode 100644 ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.html create mode 100644 ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.scss create mode 100644 ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.spec.ts create mode 100644 ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.ts diff --git a/api/src/endpoint/drStory/ownerId.ts b/api/src/endpoint/drStory/ownerId.ts index 30221c4bf..f3c48f0e6 100644 --- a/api/src/endpoint/drStory/ownerId.ts +++ b/api/src/endpoint/drStory/ownerId.ts @@ -1,4 +1,4 @@ -const Story = require('../../models/story'); +const DigitalReaderStory = require('../../models/drStory'); const User = require('../../models/user'); const mongoose = require('mongoose'); const {API404Error} = require('../../utils/APIError'); @@ -10,12 +10,12 @@ const handler = async (req, res) => { throw new API404Error(`User with id ${req.params.id} not found.`); } - const stories = await Story.find({'owner': req.params.id}).sort({$natural:-1}); + const digitalReaderStories = await DigitalReaderStory.find({'owner': req.params.id}).sort({$natural:-1}); - if (!stories) { + if (!digitalReaderStories) { throw new API404Error(`No stories written by user with id ${req.params.id} were found.`); } - return res.status(200).json(stories); + return res.status(200).json(digitalReaderStories); }; export = handler; \ No newline at end of file diff --git a/api/src/endpoint/drStory/public.ts b/api/src/endpoint/drStory/public.ts new file mode 100644 index 000000000..bbcbbce5a --- /dev/null +++ b/api/src/endpoint/drStory/public.ts @@ -0,0 +1,21 @@ +const DigitalReaderStory = require('../../models/drStory'); +//const User = require('../../models/user'); +const mongoose = require('mongoose'); +const {API404Error} = require('../../utils/APIError'); + +// get stories by owner (user) ID +const handler = async (req, res) => { + /*const user = await User.findOne({'_id': req.params.id}); + if (!user) { + throw new API404Error(`User with id ${req.params.id} not found.`); + }*/ + + const digitalReaderStories = await DigitalReaderStory.find({'public': 'true'}).sort({$natural:-1}); + + if (!digitalReaderStories) { + throw new API404Error(`No publicly available Digital Reader stories were found.`); + } + return res.status(200).json(digitalReaderStories); +}; + +export = handler; \ No newline at end of file diff --git a/api/src/endpoint/drStory/verified.ts b/api/src/endpoint/drStory/verified.ts new file mode 100644 index 000000000..00a6f5f0e --- /dev/null +++ b/api/src/endpoint/drStory/verified.ts @@ -0,0 +1,47 @@ +const DigitalReaderStory = require('../../models/drStory'); +//const User = require('../../models/user'); +const mongoose = require('mongoose'); +const {API404Error} = require('../../utils/APIError'); + +// get stories by owner (user) ID +const handler = async (req, res) => { + /*const user = await User.findOne({'_id': req.params.id}); + if (!user) { + throw new API404Error(`User with id ${req.params.id} not found.`); + }*/ + + //const digitalReaderStories = await DigitalReaderStory.find({'public': 'true'}).sort({$natural:-1}); + + /*if (!digitalReaderStories) { + throw new API404Error(`No publicly available Digital Reader stories were found.`); + }*/ + + // Get all documents whose owners carry the ADMIN role + const digitalReaderStories = await DigitalReaderStory.aggregate([ + {$lookup: { + from: 'users', + localField: 'owner', + foreignField: '_id', + as: 'ownerDocArr' + }}, + {$project: { + title: 1, + ownerDoc: {$first: '$ownerDocArr'} + }}, + {$project: { + title: 1, + ownerRole: '$ownerDoc.role' + }}, + {$match: { + ownerRole: "ADMIN" + }} + ]) + + if (!digitalReaderStories) { + throw new API404Error(`No An Scéalaí-verified Digital Reader stories were found.`); + } + + return res.status(200).json(digitalReaderStories); +}; + +export = handler; \ No newline at end of file diff --git a/api/src/routes/drStory.route.ts b/api/src/routes/drStory.route.ts index f58f33b94..abd7b93b2 100644 --- a/api/src/routes/drStory.route.ts +++ b/api/src/routes/drStory.route.ts @@ -21,10 +21,12 @@ let storyRoutes; (() => { // ENDPOINT HANDLERS // GET - /*const withId = require("../endpoint/story/withId"); + //const withId = require("../endpoint/story/withId"); - const ownerId = require("../endpoint/story/ownerId"); - const author = require("../endpoint/story/author"); + const ownerId = require("../endpoint/drStory/ownerId"); + const allPublic = require("../endpoint/drStory/public"); + const verified = require("../endpoint/drStory/verified"); + /*const author = require("../endpoint/story/author"); const feedbackAudio = require("../endpoint/story/feedbackAudio"); const countGrammarErrors = require("../endpoint/story/countGrammarErrors"); const getStoryStats = require("../endpoint/story/getStoryStats");*/ @@ -38,10 +40,12 @@ let storyRoutes; storyRoutes = makeEndpoints({ get: { - /*"/withId/:id": withId, + //"/withId/:id": withId, // '/myStudentsStory/:id': myStudentsStory, "/owner/:id": ownerId, - "/:author": author, + "/public": allPublic, + "/verified": verified, + /*"/:author": author, "/feedbackAudio/:id": feedbackAudio, "/countGrammarErrors/:id": countGrammarErrors, "/getStoryStats/allDB": getStoryStats,*/ diff --git a/ngapp/src/app/core/services/dr-story.service.ts b/ngapp/src/app/core/services/dr-story.service.ts index a1dcfa9b3..d96fd9474 100644 --- a/ngapp/src/app/core/services/dr-story.service.ts +++ b/ngapp/src/app/core/services/dr-story.service.ts @@ -11,6 +11,8 @@ import { TranslationService } from 'app/core/services/translation.service'; import config from 'abairconfig'; import { firstValueFrom, tap } from 'rxjs'; +import { DigitalReaderStory } from 'app/core/models/drStory'; + @Injectable({ providedIn: 'root' }) @@ -157,6 +159,33 @@ export class DigitalReaderStoryService { return this.http.post<{id: string}>(this.baseUrl + 'drStory/create', drStoryObj); } + getDRStoriesByOwner(owner: string) : Observable { + return this.http.get(this.baseUrl + 'drStory/owner/' + owner); + } + + getDRStoriesForLoggedInUser(): Observable { + const userDetails = this.auth.getUserDetails(); + if(!userDetails) { + return new Observable(subscriber=>{ + subscriber.next([]); + subscriber.complete(); + }); + } + return this.getDRStoriesByOwner(userDetails._id); + } + + // get all of the Digital Reader stories that have been signed off by An Scéalaí + // this amounts to all stories that were created by admins + // TODO: Implement + getAllAnScealaiVerifiedDRStories(): Observable { + return this.http.get(this.baseUrl + 'drStory/verified'); + } + + // get all of the publicly available Digital Reader stories + getAllPublicDRStories(): Observable { + return this.http.get(this.baseUrl + 'drStory/public'); + } + /* createDRStory(title: string, date: Date, dialects: Array, htmlText: string, author: string) { const drstoryObj = { diff --git a/ngapp/src/app/nav-bar/digital-reader-library/digital-reader-library.component.html b/ngapp/src/app/nav-bar/digital-reader-library/digital-reader-library.component.html index c3ef83991..5b0846c2f 100644 --- a/ngapp/src/app/nav-bar/digital-reader-library/digital-reader-library.component.html +++ b/ngapp/src/app/nav-bar/digital-reader-library/digital-reader-library.component.html @@ -1,14 +1,86 @@
-
+ -
+
+ + + + +
+ +

+
+ +

+
+ +
+
+ + + + + + + +
+
diff --git a/ngapp/src/app/nav-bar/digital-reader-library/digital-reader-library.component.scss b/ngapp/src/app/nav-bar/digital-reader-library/digital-reader-library.component.scss index 24863d862..23ab7b7f2 100644 --- a/ngapp/src/app/nav-bar/digital-reader-library/digital-reader-library.component.scss +++ b/ngapp/src/app/nav-bar/digital-reader-library/digital-reader-library.component.scss @@ -139,12 +139,9 @@ input[type="file"] { display: none; } -/*.file-upload { - border: 1px solid #ccc; - display: inline-block; - padding: 6px 12px; - -}*/ +app-dr-story-drawer { + margin: 0 auto; +} .footerLARA { display: flex; diff --git a/ngapp/src/app/nav-bar/digital-reader-library/digital-reader-library.component.ts b/ngapp/src/app/nav-bar/digital-reader-library/digital-reader-library.component.ts index 2e4c12c56..e25d51907 100644 --- a/ngapp/src/app/nav-bar/digital-reader-library/digital-reader-library.component.ts +++ b/ngapp/src/app/nav-bar/digital-reader-library/digital-reader-library.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit, Output, EventEmitter } from '@angular/core'; import { TranslationService } from 'app/core/services/translation.service'; -import { AuthenticationService } from 'app/core/services/authentication.service'; +import { AuthenticationService, UserDetails } from 'app/core/services/authentication.service'; import { firstValueFrom } from "rxjs"; import { User } from "app/core/models/user"; @@ -26,19 +26,31 @@ import { objectUtil } from 'zod'; }) export class DigitalReaderLibraryComponent implements OnInit { - @Output() isFirstDrStory = new EventEmitter(); + public anScealaiVerifiedDRStories:DigitalReaderStory[] = [] + public publicDRStories:DigitalReaderStory[] = [] + public currUsersDRStories:DigitalReaderStory[] = [] + + public userDetails:any; constructor( public ts : TranslationService, public auth: AuthenticationService, public userService: UserService, public drStoryService: DigitalReaderStoryService, - public http: HttpClient, - private dialog: MatDialog) {} + public http: HttpClient) {} async ngOnInit() { - + this.userDetails = this.auth.getUserDetails() + + this.anScealaiVerifiedDRStories = await firstValueFrom(this.drStoryService.getAllAnScealaiVerifiedDRStories()) + console.log(this.anScealaiVerifiedDRStories) + this.publicDRStories = await firstValueFrom(this.drStoryService.getAllPublicDRStories()) + console.log(this.publicDRStories) + + this.currUsersDRStories = await firstValueFrom(this.drStoryService.getDRStoriesForLoggedInUser()) + console.log(this.currUsersDRStories) + } } diff --git a/ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.html b/ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.html new file mode 100644 index 000000000..abe6b0496 --- /dev/null +++ b/ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.html @@ -0,0 +1,53 @@ +
+
+
{{ title }}
+ +
+ +
+
+ +
+
+ +
+ +
+ {{ story.updatedAt | date : "d/M/yy" }} + + + + + + +
+ +
+
+ {{ story?.title }} +
+
+ +
+ +
+
+ +
diff --git a/ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.scss b/ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.scss new file mode 100644 index 000000000..fbe283dbd --- /dev/null +++ b/ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.scss @@ -0,0 +1,104 @@ +.body { + display: flex; + width: 100%; + height: 98%; + flex-direction: column; + //max-height: 700px; +} + +.storyList { + display: flex; + flex-direction: row; + flex-grow: 1; + overflow-x: auto; + //overflow-y:visible; + //height: 350px; + height: 350px; +} + +.myStories { + color: var(--dark-text); + font-size: 16pt; + padding-bottom: 10px; + text-align: left; + //text-align: center; + font-weight: bolder; +} + +.searchBox { + min-width: 300px; +} + +.contentSection { + display: flex; + flex-direction: column; + + padding: 5px; + margin: 10px; + width: 250px; + //height: 270px; + height: 85%; + position:relative +} + +.contentSection:hover { + cursor: pointer; + background-color: #eee; + border-radius: 25px; +} + +.titleContainer { + height: 15%; + width: inherit; + position: absolute; + bottom: 20px; +} + +.contentsTitle { + color: var(--dark-text); + text-align: center; + text-decoration: none; + min-width: 50%; + //flex: 1 0 50%; + //overflow-wrap: break-word; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + overflow-y: hide; + width: inherit; + height: 100%; + + padding: 10px; + + //color: var(--dark-text); + font-weight: bolder; +} + +.contentsTitle:hover { + cursor: pointer; +} + +.contentsDate { + flex: 1 0 50%; + text-align: right; + display: block; + position: absolute; + right: 0; + top: 0; +} + +.newStoryButton { + margin-left: auto; +} + +.mat-mdc-fab.mat-accent, .mat-mdc-mini-fab.mat-accent { + background-color: var(--scealai-green); + box-shadow: none; +} + +.clickedresultCard { + background-color: #eee; + font-weight: bold; + border-radius: 5px; +} + diff --git a/ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.spec.ts b/ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.spec.ts new file mode 100644 index 000000000..42b340428 --- /dev/null +++ b/ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.spec.ts @@ -0,0 +1,27 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { HttpClientTestingModule } from '@angular/common/http/testing'; + +import { DigitalReaderStoryDrawerComponent } from './dr-story-drawer.component'; +import { MatDialogModule } from '@angular/material/dialog'; +import { FilterPipe } from '../../core/pipes/filter.pipe'; + +describe('DigitalReaderStoryDrawerComponent', () => { + let component: DigitalReaderStoryDrawerComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [ MatDialogModule, HttpClientTestingModule ], + declarations: [ DigitalReaderStoryDrawerComponent, FilterPipe ], + }) + .compileComponents(); + + fixture = TestBed.createComponent(DigitalReaderStoryDrawerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.ts b/ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.ts new file mode 100644 index 000000000..cb0d9cdc3 --- /dev/null +++ b/ngapp/src/app/nav-bar/dr-story-drawer/dr-story-drawer.component.ts @@ -0,0 +1,243 @@ +import { Component, OnInit, Output, EventEmitter, Input } from "@angular/core"; +import { firstValueFrom } from "rxjs"; +import { TranslationService } from "app/core/services/translation.service"; +import { AuthenticationService } from "app/core/services/authentication.service"; +import { DigitalReaderStoryService } from "app/core/services/dr-story.service"; +import { EngagementService } from "app/core/services/engagement.service"; +import { RecordingService } from "../../core/services/recording.service"; +import { FeedbackCommentService } from "app/core/services/feedback-comment.service"; +import { EventType } from "../../core/models/event"; +import { MatDialog, MatDialogRef } from "@angular/material/dialog"; +import { BasicDialogComponent } from "../../dialogs/basic-dialog/basic-dialog.component"; +import { DigitalReaderStory } from "app/core/models/drStory"; + +@Component({ + selector: "app-dr-story-drawer", + templateUrl: "./dr-story-drawer.component.html", + styleUrls: ["./dr-story-drawer.component.scss"], +}) +export class DigitalReaderStoryDrawerComponent implements OnInit { + stories: DigitalReaderStory[] = []; + dialogRef: MatDialogRef; + lastClickedStoryId: string = ""; + searchText: string = ""; // used to filter stories in search bar + @Output() drStoryEmitter = new EventEmitter(); + @Output() hasFeedback = new EventEmitter(); + @Output() titleUpdated = new EventEmitter(); + @Output() storiesLoaded = new EventEmitter(); + @Output() isFirstStory = new EventEmitter(); + + @Input() title = ''; + @Input() storyList = []; + + constructor( + public ts: TranslationService, + private auth: AuthenticationService, + private drStoryService: DigitalReaderStoryService, + private engagement: EngagementService, + private recordingService: RecordingService, + private feedbackCommentService: FeedbackCommentService, + private dialog: MatDialog + ) {} + + ngOnInit() { + this.getStories(); + } + + /** + * Get list of stories for the user and emit when done loading + */ + async getStories() { + this.stories = ( + await firstValueFrom(this.drStoryService.getDRStoriesForLoggedInUser()) + ).map((storyData) => new DigitalReaderStory().fromJSON(storyData)); + + /*if (this.stories.length > 0) { + this.lastClickedStoryId = this.stories[0]._id; + // delay seting the currently selected story until the next tick of the event loop + setTimeout(() => { + this.setStory(this.stories[0]); + }); + }*/ + setTimeout(() => { + this.storiesLoaded.emit(true); + }); + } + + /** + * Set the current story to the selected one from the story list + * @param story Selected story from HTML + */ + //setStory(story: DigitalReaderStory){} + openStory(story: DigitalReaderStory){} + /*setStory(story: Story) { + if (story.htmlText == null) { + story.htmlText = story.text; + } + // emit selected story to dashboard + this.storyEmitter.emit(story); + + // emit whether or not the story has any feedback + this.hasFeedback.emit(this.storyHasFeedback(story)) + + // set css for selecting a story in the side nav + let id = story._id; + let storyElement = document.getElementById(id); + + if (storyElement) { + // remove css highlighting for currently highlighted story + if (this.lastClickedStoryId) { + document.getElementById(this.lastClickedStoryId)?.classList.remove("clickedresultCard"); + } + this.lastClickedStoryId = id; + // add css highlighting to the newly clicked story + storyElement.classList.add("clickedresultCard"); + } + }*/ + + /** + * Returns true if the story has feedback left from the teacher + * @param story story selected from list + * @returns true or false + */ + /*storyHasFeedback(story: Story): boolean { + return story.feedback.hasComments || story.feedback.feedbackMarkup != null + }*/ + + /** + * Create a new story + */ + createNewStory(){} + /*createNewStory() { + this.isFirstStory.emit(this.stories.length == 0); + this.dialogRef = this.dialog.open(BasicDialogComponent, { + data: { + title: this.ts.l.story_details, + type: "select", + data: [ + this.ts.l.enter_title, + [this.ts.l.connacht, this.ts.l.munster, this.ts.l.ulster], + [this.ts.l.title, this.ts.l.dialect], + ], + confirmText: this.ts.l.save_details, + cancelText: this.ts.l.cancel, + }, + width: "50vh", + }); + + this.dialogRef.afterClosed().subscribe(async (res: any) => { + this.dialogRef = undefined; + console.log(res) + if (res) { + if (res[0]) { + let dialect = "connemara"; + if (res[1] == this.ts.l.munster) dialect = "kerry"; + if (res[1] == this.ts.l.ulster) dialect = "donegal"; + const user = this.auth.getUserDetails(); + if (!user) { + console.log("Can't save story, current user is null"); + return; + } + this.storyService + .saveStory(res[0], new Date(), dialect, "", user.username, false ) + .subscribe({ + next: () => { + this.getStories(); + }, + error: () => { + alert("Not able to create a new story"); + }, + }); + } else { + alert(this.ts.l.title_required); + } + } + }); + }*/ + + /** + * Open a dialog asking the user if they really want to delte their story + * Call the function to delete the story if the user clicks 'yes' + * @param id story id to be deleted + */ + /*openDeleteStoryDialog(id: string) { + this.dialogRef = this.dialog.open(BasicDialogComponent, { + data: { + title: this.ts.l.delete_story, + message: this.ts.l.are_you_sure_delete_story, + confirmText: this.ts.l.yes, + cancelText: this.ts.l.no, + }, + width: "50vh", + }); + + this.dialogRef.afterClosed().subscribe(async (res: any) => { + this.dialogRef = undefined; + if (res) { + this.deleteStory(id); + } + }); + }*/ + + /** + * Delete the given story and any associated recordings + * Set the new 'current story' => next one in the list, or first one + * if the last story in the list was deleted + * @param id story id to be deleted + */ + /*deleteStory(id: string) { + // remove any associated recordings + this.recordingService.deleteStoryRecordingAudio(id).subscribe((_) => {}); + this.recordingService.deleteStoryRecording(id).subscribe((_) => {}); + + // remove any associated feedback comments + this.feedbackCommentService.deleteFeedbackCommentsForStory(id).subscribe((_) => {}); + + // get index of story to be deleted within story list + const storyIndex = this.stories.findIndex((story) => story._id === id); + + // delete the story + this.storyService.deleteStory(id).subscribe((_) => { + this.engagement.addEvent(EventType["DELETE-STORY"], { storyId: id }); + + // reset the story list to empty if list contains only one story + // If we have 2+ stories, delete the story for deletion, and set the new current story to the first in the list + this.stories.splice(storyIndex, 1); + this.stories.length ? this.setStory(this.stories[0]) : this.storyEmitter.emit(); + }); + }*/ + + /** + * Make the div containing the story title editable so the student can + * rename their story. Autofocus this editable div after making editable + * @param divId id of the div for the story title + */ + /*makeTitleDivEditable(divId: number) { + console.log(typeof divId) + const contentEditableDiv = document.getElementById(String(divId)) as HTMLDivElement; + contentEditableDiv.setAttribute("contenteditable", "true"); + // auto-focus the div for editing, need to use setTimeout so event is applied + window.setTimeout(() => contentEditableDiv.focus(), 0); + }*/ + + /** + * Remove the editable attribute from the div containing the story title + * Save the updated title for the story if changes were made + * @param divId id of the div for the story title + */ + saveStoryTitle(divId: number, selectedStory: DigitalReaderStory){} + /*saveStoryTitle(divId: number, selectedStory: Story) { + const contentEditableDiv = document.getElementById(String(divId)) as HTMLDivElement; + if (!contentEditableDiv || !selectedStory) return; + contentEditableDiv.setAttribute("contenteditable", "false"); + // only update the title if changes have been made + if (selectedStory.title.trim() != contentEditableDiv!.textContent!.trim()) { + selectedStory.title = contentEditableDiv.textContent!; + this.storyService.updateTitle(selectedStory._id, selectedStory.title.trim()) + .subscribe({ + next: () => { this.titleUpdated.emit(selectedStory.title.trim()); }, + error: () => console.log("error updating title"), + }); + } + }*/ +} diff --git a/ngapp/src/app/nav-bar/nav-bar.module.ts b/ngapp/src/app/nav-bar/nav-bar.module.ts index d4b95e6ca..4af1ed7aa 100644 --- a/ngapp/src/app/nav-bar/nav-bar.module.ts +++ b/ngapp/src/app/nav-bar/nav-bar.module.ts @@ -5,7 +5,10 @@ import { MatCardModule } from '@angular/material/card'; import { MatMenuModule } from '@angular/material/menu'; import { MatIconModule } from '@angular/material/icon'; -import { MatCheckboxModule } from '@angular/material/checkbox'; // added by David 04/07/2024 +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatTabsModule } from '@angular/material/tabs'; +import { MatButtonModule } from '@angular/material/button'; +import { MatDividerModule } from '@angular/material/divider'; import { NavBarRoutingModule } from './nav-bar-routing.module'; import { NavBarComponent } from './nav-bar/nav-bar.component'; @@ -23,6 +26,8 @@ import { TeamComponent } from './team/team.component'; import { ReportAnIssueComponent } from './report-an-issue/report-an-issue.component'; import { ResourcesComponent } from './resources/resources.component'; import { DigitalReaderComponent } from './digital-reader/digital-reader.component'; +import { DigitalReaderLibraryComponent } from './digital-reader-library/digital-reader-library.component'; +import { DigitalReaderStoryDrawerComponent } from './dr-story-drawer/dr-story-drawer.component'; import { AboutTaidhginComponent } from './about-taidhgin/about-taidhgin.component'; import { FiosComponent } from './fios/fios.component'; @@ -38,6 +43,8 @@ import { FiosComponent } from './fios/fios.component'; ReportAnIssueComponent, ResourcesComponent, DigitalReaderComponent, + DigitalReaderLibraryComponent, + DigitalReaderStoryDrawerComponent, AboutTaidhginComponent, FiosComponent ], @@ -52,7 +59,10 @@ import { FiosComponent } from './fios/fios.component'; MatMenuModule, MatIconModule, MatCheckboxModule, // added by David 04/07/2024 - StudentModule // added by David 05/07/2024 + StudentModule, // added by David 05/07/2024 + MatTabsModule, + MatButtonModule, + MatDividerModule ] }) export class NavBarModule { } diff --git a/ngapp/src/app/student/student.module.ts b/ngapp/src/app/student/student.module.ts index ca1b99400..6e2ece535 100644 --- a/ngapp/src/app/student/student.module.ts +++ b/ngapp/src/app/student/student.module.ts @@ -50,6 +50,9 @@ import { SafeHtmlPipe } from 'app/core/pipes/safe-html.pipe'; SynthesisDrawerComponent, HomePageComponent ], + exports: [ + FilterPipe + ], imports: [ CommonModule, StudentRoutingModule, diff --git a/ngapp/src/app/translation.ts b/ngapp/src/app/translation.ts index cb9250825..3949ad108 100644 --- a/ngapp/src/app/translation.ts +++ b/ngapp/src/app/translation.ts @@ -218,6 +218,12 @@ const translations = { processing: { ga: 'Á phróiseáil', en: 'Processing' }, + verified_dr_stories: { + ga: 'Scéalta Bailí', + en: 'Verified Stories' }, + public_dr_stories: { + ga: 'Scéalta an Phobail', + en: 'Community Stories' }, contents: { ga: 'Clár Scéalta', en: 'Contents' },