mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-08 17:06:15 -08:00
fix(m3u): the cast row renders plain entries where no actor page exists
With TMDB enrichment the M3U movie details showed every person as a focusable button whose activation did nothing, since the M3U library has no actor page. The row takes an `interactive` input and the M3U details turn it off. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
1 parent
aaa86f8c9c
commit
bc034cf163
3 files changed
+66
-3
No files matched your search
+6
-1
@@ -56,6 +56,11 @@
|
||||
}
|
||||
|
||||
<div detail-extras>
|
||||
<app-cast-crew-row [cast]="cast()" [directors]="directorMembers()" />
|
||||
<!-- M3U has no actor page: the people stay plain entries -->
|
||||
<app-cast-crew-row
|
||||
[cast]="cast()"
|
||||
[directors]="directorMembers()"
|
||||
[interactive]="false"
|
||||
/>
|
||||
</div>
|
||||
</app-portal-detail-shell>
|
||||
@@ -0,0 +1,56 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import type { TmdbEnrichedCastMember } from '@iptvnator/shared/interfaces';
|
||||
import { CastCrewRowComponent } from './cast-crew-row.component';
|
||||
|
||||
const ACTOR: TmdbEnrichedCastMember = {
|
||||
name: 'Ada Vance',
|
||||
character: 'Captain',
|
||||
tmdbPersonId: 501,
|
||||
} as TmdbEnrichedCastMember;
|
||||
|
||||
describe('CastCrewRowComponent', () => {
|
||||
let fixture: ComponentFixture<CastCrewRowComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [CastCrewRowComponent, TranslateModule.forRoot()],
|
||||
}).compileComponents();
|
||||
fixture = TestBed.createComponent(CastCrewRowComponent);
|
||||
fixture.componentRef.setInput('cast', [ACTOR]);
|
||||
});
|
||||
|
||||
function person(): HTMLElement {
|
||||
const element = (fixture.nativeElement as HTMLElement).querySelector(
|
||||
'.person'
|
||||
);
|
||||
expect(element).not.toBeNull();
|
||||
return element as HTMLElement;
|
||||
}
|
||||
|
||||
it('offers a person with a TMDB id as a button that opens the actor page', () => {
|
||||
const personSelected = jest.fn();
|
||||
fixture.componentInstance.personSelected.subscribe(personSelected);
|
||||
fixture.detectChanges();
|
||||
|
||||
expect(person().getAttribute('role')).toBe('button');
|
||||
expect(person().getAttribute('tabindex')).toBe('0');
|
||||
person().click();
|
||||
expect(personSelected).toHaveBeenCalledWith(ACTOR);
|
||||
});
|
||||
|
||||
it('renders plain entries for a host without an actor page', () => {
|
||||
const personSelected = jest.fn();
|
||||
fixture.componentInstance.personSelected.subscribe(personSelected);
|
||||
fixture.componentRef.setInput('interactive', false);
|
||||
fixture.detectChanges();
|
||||
|
||||
// A focusable button that does nothing would mislead mouse and
|
||||
// keyboard users alike.
|
||||
expect(person().getAttribute('role')).toBeNull();
|
||||
expect(person().getAttribute('tabindex')).toBeNull();
|
||||
expect(person().classList.contains('person--clickable')).toBe(false);
|
||||
person().click();
|
||||
expect(personSelected).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
@@ -22,7 +22,7 @@ export function scrollToCastCrewRow(): void {
|
||||
* "Cast & crew" row under the hero: 72px round avatars with the full name
|
||||
* and the character (or "Director"), the director first, initials when a
|
||||
* person has no photo. A click on a person with a TMDB id opens the actor
|
||||
* page through the host.
|
||||
* page through the host; a host without one renders plain entries.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'app-cast-crew-row',
|
||||
@@ -35,6 +35,8 @@ export class CastCrewRowComponent {
|
||||
readonly cast = input<readonly TmdbEnrichedCastMember[]>([]);
|
||||
readonly directors = input<readonly TmdbEnrichedCastMember[]>([]);
|
||||
readonly headingId = input<string | null>('detail-cast-crew');
|
||||
/** False when the host has no actor page: nobody becomes a button that does nothing. */
|
||||
readonly interactive = input(true);
|
||||
|
||||
readonly personSelected = output<TmdbEnrichedCastMember>();
|
||||
|
||||
@@ -49,7 +51,7 @@ export class CastCrewRowComponent {
|
||||
);
|
||||
|
||||
isClickable(entry: CastCrewEntry): boolean {
|
||||
return !!entry.member.tmdbPersonId;
|
||||
return this.interactive() && !!entry.member.tmdbPersonId;
|
||||
}
|
||||
|
||||
select(entry: CastCrewEntry): void {
|
||||
|
||||
Reference in new issue
Block a user