From 9e1bcaf58182dc6ca65cdea3e58b21a669464c6a Mon Sep 17 00:00:00 2001 From: Noel De Martin Date: Wed, 28 Jun 2023 12:17:10 +0200 Subject: [PATCH] MOBILE-3371 core: Implement course image component --- src/assets/storybook/courses.json | 1 + src/assets/storybook/geopattern.svg | 2 + src/assets/storybook/sites/school.json | 1 + src/core/components/components.module.ts | 3 + .../components/course-image/course-image.html | 5 + .../components/course-image/course-image.scss | 65 +++++++++++ .../components/course-image/course-image.ts | 81 ++++++++++++++ .../stories/components/components.module.ts | 4 + .../course-image-cards-page.html | 22 ++++ .../course-image-cards-page.scss | 16 +++ .../course-image-cards-page.ts | 28 +++++ .../course-image-list-page.html | 19 ++++ .../course-image-list-page.ts | 27 +++++ .../stories/course-image.stories.ts | 104 ++++++++++++++++++ src/storybook/storybook.module.ts | 13 +++ src/storybook/stubs/classes/site.ts | 57 ++++++++++ src/storybook/stubs/classes/sqlitedb.ts | 32 ++++++ src/storybook/stubs/services/db.ts | 35 ++++++ src/storybook/stubs/services/filepool.ts | 32 ++++++ src/storybook/stubs/services/http.ts | 38 +++++++ src/storybook/stubs/services/sites.ts | 43 ++++++++ 21 files changed, 628 insertions(+) create mode 100644 src/assets/storybook/courses.json create mode 100644 src/assets/storybook/geopattern.svg create mode 100644 src/assets/storybook/sites/school.json create mode 100644 src/core/components/course-image/course-image.html create mode 100644 src/core/components/course-image/course-image.scss create mode 100644 src/core/components/course-image/course-image.ts create mode 100644 src/core/components/stories/components/course-image-cards-page/course-image-cards-page.html create mode 100644 src/core/components/stories/components/course-image-cards-page/course-image-cards-page.scss create mode 100644 src/core/components/stories/components/course-image-cards-page/course-image-cards-page.ts create mode 100644 src/core/components/stories/components/course-image-list-page/course-image-list-page.html create mode 100644 src/core/components/stories/components/course-image-list-page/course-image-list-page.ts create mode 100644 src/core/components/stories/course-image.stories.ts create mode 100644 src/storybook/stubs/classes/site.ts create mode 100644 src/storybook/stubs/classes/sqlitedb.ts create mode 100644 src/storybook/stubs/services/db.ts create mode 100644 src/storybook/stubs/services/filepool.ts create mode 100644 src/storybook/stubs/services/http.ts create mode 100644 src/storybook/stubs/services/sites.ts diff --git a/src/assets/storybook/courses.json b/src/assets/storybook/courses.json new file mode 100644 index 000000000..81b9390e0 --- /dev/null +++ b/src/assets/storybook/courses.json @@ -0,0 +1 @@ +[{"id":1,"courseimage":"https://picsum.photos/500/500","shortname":"Moodle and Mountaineering","summary":"This course will introduce you to the basics of Alpine Mountaineering, while at the same time highlighting some of the great features of Moodle."},{"id":2,"courseimage":"assets/storybook/geopattern.svg","shortname":"Digital Literacy","summary":"This course explores Digital Literacy and its importance for teachers and students. The course is optimised for the Moodle App. Please try it out!"},{"id":3,"shortname":"Class and Conflict in World Cinema","summary":"In this module we will analyse two very significant films - City of God and La Haine, both of which depict violent lives in poor conditions, the former in the favelas of Brazil and the latter in a Parisian banlieue. We will look at how conflict and class are portrayed, focusing particularly on the use of mise en scène."}] diff --git a/src/assets/storybook/geopattern.svg b/src/assets/storybook/geopattern.svg new file mode 100644 index 000000000..60e7e8a9d --- /dev/null +++ b/src/assets/storybook/geopattern.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/assets/storybook/sites/school.json b/src/assets/storybook/sites/school.json new file mode 100644 index 000000000..1260527ba --- /dev/null +++ b/src/assets/storybook/sites/school.json @@ -0,0 +1 @@ +{"id":"123456","info":{"version":"2022041900","sitename":"School","username":"barbara","firstname":"Barbara","lastname":"Gardner","fullname":"Barbara Gardner","lang":"en","userid":1,"siteurl":"https://campus.example.edu","userpictureurl":"","functions":[]}} diff --git a/src/core/components/components.module.ts b/src/core/components/components.module.ts index 4609c0f04..fc64175b1 100644 --- a/src/core/components/components.module.ts +++ b/src/core/components/components.module.ts @@ -64,6 +64,7 @@ import { CoreMessageComponent } from './message/message'; import { CoreGroupSelectorComponent } from './group-selector/group-selector'; import { CoreRefreshButtonModalComponent } from './refresh-button-modal/refresh-button-modal'; import { CoreSheetModalComponent } from '@components/sheet-modal/sheet-modal'; +import { CoreCourseImageComponent } from '@components/course-image/course-image'; @NgModule({ declarations: [ @@ -75,6 +76,7 @@ import { CoreSheetModalComponent } from '@components/sheet-modal/sheet-modal'; CoreContextMenuComponent, CoreContextMenuItemComponent, CoreContextMenuPopoverComponent, + CoreCourseImageComponent, CoreDownloadRefreshComponent, CoreDynamicComponent, CoreEmptyBoxComponent, @@ -128,6 +130,7 @@ import { CoreSheetModalComponent } from '@components/sheet-modal/sheet-modal'; CoreContextMenuComponent, CoreContextMenuItemComponent, CoreContextMenuPopoverComponent, + CoreCourseImageComponent, CoreDownloadRefreshComponent, CoreDynamicComponent, CoreEmptyBoxComponent, diff --git a/src/core/components/course-image/course-image.html b/src/core/components/course-image/course-image.html new file mode 100644 index 000000000..6251e1eea --- /dev/null +++ b/src/core/components/course-image/course-image.html @@ -0,0 +1,5 @@ + + + + diff --git a/src/core/components/course-image/course-image.scss b/src/core/components/course-image/course-image.scss new file mode 100644 index 000000000..5bd16990d --- /dev/null +++ b/src/core/components/course-image/course-image.scss @@ -0,0 +1,65 @@ +@import "~theme/globals"; + +:host { + --core-image-radius: var(--core-courseimage-radius); + --core-image-size: 60px; + + display: flex; + justify-content: center; + align-items: center; + background: var(--course-color, white); + border-radius: var(--core-image-radius); + + @for $i from 0 to length($core-course-image-background) { + &.course-color-#{$i} { + --course-color: var(--core-course-color-#{$i}); + --course-color-tint: var(--core-course-color-#{$i}-tint); + } + } + + ion-icon { + --padding: 12px; + + padding: var(--padding); + font-size: calc(var(--core-image-size) - var(--padding) * 2); + color: var(--course-color-tint); + } + + ion-avatar { + --border-radius: var(--core-image-radius); + width: var(--core-image-size); + height: var(--core-image-size); + + img { + background: transparent; + } + + } + + img[src$=".svg"] { + min-width: 100%; + } + + &.fill-container { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + + --core-image-radius: 0px; + --core-image-size: 100%; + + ion-icon { + opacity: 0.5; + width: 80px; + height: 80px; + } + + } + +} + +:host-context(ion-item) { + @include margin(6px, 8px, 6px, 0px); +} diff --git a/src/core/components/course-image/course-image.ts b/src/core/components/course-image/course-image.ts new file mode 100644 index 000000000..dc440b81a --- /dev/null +++ b/src/core/components/course-image/course-image.ts @@ -0,0 +1,81 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, Input, ElementRef, OnInit, OnChanges, HostBinding } from '@angular/core'; +import { CoreCourseListItem } from '@features/courses/services/courses'; +import { CoreCoursesHelper } from '@features/courses/services/courses-helper'; +import { CoreColors } from '@singletons/colors'; + +@Component({ + selector: 'core-course-image', + templateUrl: 'course-image.html', + styleUrls: ['./course-image.scss'], +}) +export class CoreCourseImageComponent implements OnInit, OnChanges { + + @Input() course!: CoreCourseListItem; + @Input() fill = false; + + protected element: HTMLElement; + + constructor(element: ElementRef) { + this.element = element.nativeElement; + } + + @HostBinding('class.fill-container') + get fillContainer(): boolean { + return this.fill; + } + + /** + * @inheritdoc + */ + ngOnInit(): void { + this.setCourseColor(); + } + + /** + * @inheritdoc + */ + ngOnChanges(): void { + this.setCourseColor(); + } + + /** + * Removes the course image set because it cannot be loaded and set the fallback icon color. + */ + loadFallbackCourseIcon(): void { + this.course.courseimage = undefined; + + // Set the color because it won't be set at this point. + this.setCourseColor(); + } + + /** + * Set course color. + */ + protected async setCourseColor(): Promise { + await CoreCoursesHelper.loadCourseColorAndImage(this.course); + + if (this.course.color) { + this.element.style.setProperty('--course-color', this.course.color); + + const tint = CoreColors.lighter(this.course.color, 50); + this.element.style.setProperty('--course-color-tint', tint); + } else if(this.course.colorNumber !== undefined) { + this.element.classList.add('course-color-' + this.course.colorNumber); + } + } + +} diff --git a/src/core/components/stories/components/components.module.ts b/src/core/components/stories/components/components.module.ts index af6de43cb..e70834d30 100644 --- a/src/core/components/stories/components/components.module.ts +++ b/src/core/components/stories/components/components.module.ts @@ -19,9 +19,13 @@ import { StorybookModule } from '@/storybook/storybook.module'; import { CoreSearchComponentsModule } from '@features/search/components/components.module'; import { CoreComponentsModule } from '@components/components.module'; import { CommonModule } from '@angular/common'; +import { CoreCourseImageCardsPageComponent } from '@components/stories/components/course-image-cards-page/course-image-cards-page'; +import { CoreCourseImageListPageComponent } from '@components/stories/components/course-image-list-page/course-image-list-page'; @NgModule({ declarations: [ + CoreCourseImageCardsPageComponent, + CoreCourseImageListPageComponent, CoreEmptyBoxPageComponent, CoreEmptyBoxWrapperComponent, ], diff --git a/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.html b/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.html new file mode 100644 index 000000000..90514a8e3 --- /dev/null +++ b/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.html @@ -0,0 +1,22 @@ + + + + +

Course Cards

+
+
+
+ + +
+ +
+ + {{ course.shortname }} + + + {{ course.summary }} + +
+
+
diff --git a/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.scss b/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.scss new file mode 100644 index 000000000..23f07c6fd --- /dev/null +++ b/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.scss @@ -0,0 +1,16 @@ +:host { + + ion-card { + max-width: 350px; + margin-right: auto; + margin-left: auto; + } + + .course-image-wrapper { + width: 100%; + height: 0; + padding-top: 40%; + position: relative; + } + +} diff --git a/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.ts b/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.ts new file mode 100644 index 000000000..f2b6b0323 --- /dev/null +++ b/src/core/components/stories/components/course-image-cards-page/course-image-cards-page.ts @@ -0,0 +1,28 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component } from '@angular/core'; +import { CoreCourseListItem } from '@features/courses/services/courses'; +import courses from '@/assets/storybook/courses.json'; + +@Component({ + selector: 'core-course-image-cards-page', + templateUrl: 'course-image-cards-page.html', + styleUrls: ['./course-image-cards-page.scss'], +}) +export class CoreCourseImageCardsPageComponent { + + courses: Partial[] = courses; + +} diff --git a/src/core/components/stories/components/course-image-list-page/course-image-list-page.html b/src/core/components/stories/components/course-image-list-page/course-image-list-page.html new file mode 100644 index 000000000..ec47e63fb --- /dev/null +++ b/src/core/components/stories/components/course-image-list-page/course-image-list-page.html @@ -0,0 +1,19 @@ + + + + +

Courses List

+
+
+
+ + + + + + {{ course.shortname }} + + + + +
diff --git a/src/core/components/stories/components/course-image-list-page/course-image-list-page.ts b/src/core/components/stories/components/course-image-list-page/course-image-list-page.ts new file mode 100644 index 000000000..cf66b61f0 --- /dev/null +++ b/src/core/components/stories/components/course-image-list-page/course-image-list-page.ts @@ -0,0 +1,27 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component } from '@angular/core'; +import { CoreCourseListItem } from '@features/courses/services/courses'; +import courses from '@/assets/storybook/courses.json'; + +@Component({ + selector: 'core-course-image-list-page', + templateUrl: 'course-image-list-page.html', +}) +export class CoreCourseImageListPageComponent { + + courses: Partial[] = courses; + +} diff --git a/src/core/components/stories/course-image.stories.ts b/src/core/components/stories/course-image.stories.ts new file mode 100644 index 000000000..cd919a6fe --- /dev/null +++ b/src/core/components/stories/course-image.stories.ts @@ -0,0 +1,104 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Meta, moduleMetadata } from '@storybook/angular'; + +import { story } from '@/storybook/utils/helpers'; + +import { CoreCourseImageComponent } from '@components/course-image/course-image'; +import { APP_INITIALIZER } from '@angular/core'; +import { CoreSitesStub } from '@/storybook/stubs/services/sites'; +import { CoreCourseImageListPageComponent } from '@components/stories/components/course-image-list-page/course-image-list-page'; +import { CoreComponentsStorybookModule } from '@components/stories/components/components.module'; +import { CoreCourseImageCardsPageComponent } from '@components/stories/components/course-image-cards-page/course-image-cards-page'; + +interface Args { + type: 'image' | 'geopattern' | 'color'; + fill: boolean; +} + +export default { + title: 'Core/Course Image', + component: CoreCourseImageComponent, + decorators: [ + moduleMetadata({ + imports: [CoreComponentsStorybookModule], + providers: [ + { + provide: APP_INITIALIZER, + multi: true, + useValue: () => { + const site = CoreSitesStub.getRequiredCurrentSite(); + + site.stubWSResponse('tool_mobile_get_config', { + settings: [ + { name: 'core_admin_coursecolor1', value: '#F9B000' }, + { name: 'core_admin_coursecolor2', value: '#EF4B00' }, + { name: 'core_admin_coursecolor3', value: '#4338FB' }, + { name: 'core_admin_coursecolor4', value: '#E142FB' }, + { name: 'core_admin_coursecolor5', value: '#FF0064' }, + { name: 'core_admin_coursecolor6', value: '#FF0F18' }, + { name: 'core_admin_coursecolor7', value: '#039B06' }, + { name: 'core_admin_coursecolor8', value: '#039B88' }, + { name: 'core_admin_coursecolor9', value: '#EF009B' }, + { name: 'core_admin_coursecolor10', value: '#020B6E' }, + ], + warnings: [], + }); + }, + }, + ], + }), + ], + argTypes: { + type: { + control: { + type: 'select', + options: ['image', 'geopattern', 'color'], + }, + }, + }, + args: { + type: 'image', + fill: false, + }, +}; + +const Template = story(({ type, ...args }) => { + const getImageSource = () => { + switch (type) { + case 'image': + return 'https://picsum.photos/500/500'; + case 'geopattern': + return 'assets/storybook/geopattern.svg'; + case 'color': + return undefined; + } + }; + + return { + component: CoreCourseImageComponent, + props: { + ...args, + course: { + id: 1, + courseimage: getImageSource(), + }, + }, + }; +}); + +export const Primary = story(Template); +export const ListPage = story(() => ({ component: CoreCourseImageListPageComponent })); +export const CardsPage = story(() => ({ component: CoreCourseImageCardsPageComponent })); diff --git a/src/storybook/storybook.module.ts b/src/storybook/storybook.module.ts index cd8679cd5..f4bf199c6 100644 --- a/src/storybook/storybook.module.ts +++ b/src/storybook/storybook.module.ts @@ -20,6 +20,14 @@ import { TranslateLoader, TranslateModule } from '@ngx-translate/core'; import englishTranslations from '@/assets/lang/en.json'; import { CoreApplicationInitStatus } from '@classes/application-init-status'; import { Translate } from '@singletons'; +import { CoreSitesProviderStub, CoreSitesStub } from '@/storybook/stubs/services/sites'; +import { CoreSitesProvider } from '@services/sites'; +import { CoreDbProviderStub } from '@/storybook/stubs/services/db'; +import { CoreDbProvider } from '@services/db'; +import { CoreFilepoolProviderStub } from '@/storybook/stubs/services/filepool'; +import { CoreFilepoolProvider } from '@services/filepool'; +import { HttpClientStub } from '@/storybook/stubs/services/http'; +import { HttpClient } from '@angular/common/http'; // For translate loader. AoT requires an exported function for factories. export class StaticTranslateLoader extends TranslateLoader { @@ -45,12 +53,17 @@ export class StaticTranslateLoader extends TranslateLoader { ], providers: [ { provide: ApplicationInitStatus, useClass: CoreApplicationInitStatus }, + { provide: CoreSitesProvider, useClass: CoreSitesProviderStub }, + { provide: CoreDbProvider, useClass: CoreDbProviderStub }, + { provide: CoreFilepoolProvider, useClass: CoreFilepoolProviderStub }, + { provide: HttpClient, useClass: HttpClientStub }, { provide: APP_INITIALIZER, multi: true, useValue: () => { Translate.setDefaultLang('en'); Translate.use('en'); + CoreSitesStub.stubCurrentSite(); }, }, ], diff --git a/src/storybook/stubs/classes/site.ts b/src/storybook/stubs/classes/site.ts new file mode 100644 index 000000000..12d8f89c2 --- /dev/null +++ b/src/storybook/stubs/classes/site.ts @@ -0,0 +1,57 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { CoreSite, CoreSiteConfigResponse, CoreSiteInfo, CoreSiteWSPreSets, WSObservable } from '@classes/site'; +import { of } from 'rxjs'; + +export interface CoreSiteFixture { + id: string; + info: CoreSiteInfo; +} + +export class CoreSiteStub extends CoreSite { + + protected wsStubs: Record = {}; + + constructor (fixture: CoreSiteFixture) { + super(fixture.id, fixture.info.siteurl, undefined, fixture.info); + + this.stubWSResponse('tool_mobile_get_config', { + settings: [], + warnings: [], + }); + } + + /** + * @inheritdoc + */ + readObservable(wsFunction: string, data: unknown, preSets?: CoreSiteWSPreSets): WSObservable { + if (wsFunction in this.wsStubs) { + return of(this.wsStubs[wsFunction] as T); + } + + return super.readObservable(wsFunction, data, preSets); + } + + /** + * Prepare as stubbed response for a given WS. + * + * @param wsFunction WS function. + * @param response Response. + */ + stubWSResponse(wsFunction: string, response: T): void { + this.wsStubs[wsFunction] = response; + } + +} diff --git a/src/storybook/stubs/classes/sqlitedb.ts b/src/storybook/stubs/classes/sqlitedb.ts new file mode 100644 index 000000000..94d81b5a1 --- /dev/null +++ b/src/storybook/stubs/classes/sqlitedb.ts @@ -0,0 +1,32 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { SQLiteDB } from '@classes/sqlitedb'; +import { SQLiteObject } from '@ionic-native/sqlite/ngx'; + +/** + * SQlite database stub. + */ +export class SQLiteDBStub extends SQLiteDB { + + /** + * @inheritdoc + */ + async createDatabase(): Promise { + return new Proxy({ + executeSql: () => Promise.resolve({ insertId: Math.random().toString() }), + }, {}) as unknown as SQLiteObject; + } + +} diff --git a/src/storybook/stubs/services/db.ts b/src/storybook/stubs/services/db.ts new file mode 100644 index 000000000..e74c90bb2 --- /dev/null +++ b/src/storybook/stubs/services/db.ts @@ -0,0 +1,35 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { SQLiteDBStub } from '@/storybook/stubs/classes/sqlitedb'; +import { SQLiteDB } from '@classes/sqlitedb'; +import { CoreDbProvider } from '@services/db'; + +/** + * Database provider stub. + */ +export class CoreDbProviderStub extends CoreDbProvider { + + /** + * @inheritdoc + */ + getDB(name: string, forceNew?: boolean): SQLiteDB { + if (this.dbInstances[name] === undefined || forceNew) { + this.dbInstances[name] = new SQLiteDBStub(name); + } + + return this.dbInstances[name]; + } + +} diff --git a/src/storybook/stubs/services/filepool.ts b/src/storybook/stubs/services/filepool.ts new file mode 100644 index 000000000..d5c604aad --- /dev/null +++ b/src/storybook/stubs/services/filepool.ts @@ -0,0 +1,32 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { makeSingleton } from '@singletons'; +import { CoreFilepoolProvider } from '@services/filepool'; + +/** + * Filepool provider stub. + */ +export class CoreFilepoolProviderStub extends CoreFilepoolProvider { + + /** + * @inheritdoc + */ + async getSrcByUrl(siteId: string, fileUrl: string): Promise { + return fileUrl; + } + +} + +export const CoreFilepoolStub = makeSingleton(CoreFilepoolProvider); diff --git a/src/storybook/stubs/services/http.ts b/src/storybook/stubs/services/http.ts new file mode 100644 index 000000000..55e397d72 --- /dev/null +++ b/src/storybook/stubs/services/http.ts @@ -0,0 +1,38 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { makeSingleton } from '@singletons'; +import { HttpClient, HttpHandler } from '@angular/common/http'; +import { from, Observable } from 'rxjs'; + +/** + * Http service stub. + */ +export class HttpClientStub extends HttpClient { + + constructor() { + super(null as unknown as HttpHandler); + } + + /** + * @inheritdoc + */ + // eslint-disable-next-line @typescript-eslint/no-explicit-any + get(url: string): Observable { + return from(fetch(url).then(response => response.text())); + } + +} + +export const HttpStub = makeSingleton(HttpClient); diff --git a/src/storybook/stubs/services/sites.ts b/src/storybook/stubs/services/sites.ts new file mode 100644 index 000000000..25f32541a --- /dev/null +++ b/src/storybook/stubs/services/sites.ts @@ -0,0 +1,43 @@ +// (C) Copyright 2015 Moodle Pty Ltd. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import school from '@/assets/storybook/sites/school.json'; +import { CoreSiteFixture, CoreSiteStub } from '@/storybook/stubs/classes/site'; +import { CoreSitesProvider } from '@services/sites'; +import { makeSingleton } from '@singletons'; + +/** + * Sites provider stub. + */ +export class CoreSitesProviderStub extends CoreSitesProvider { + + /** + * @inheritdoc + */ + getRequiredCurrentSite!: () => CoreSiteStub; + + /** + * @inheritdoc + */ + stubCurrentSite(fixture?: CoreSiteFixture): CoreSiteStub { + if (!this.currentSite) { + this.currentSite = new CoreSiteStub(fixture ?? school); + } + + return this.getRequiredCurrentSite(); + } + +} + +export const CoreSitesStub = makeSingleton(CoreSitesProvider);