Skip to content

Conversation

@flyspraysandwich
Copy link
Contributor

@flyspraysandwich flyspraysandwich commented May 8, 2025

ADO card: ☑️ AB#XXXX

Elab notes/AC: 📃 Detail Page Video Player - Google Docs

  • Has this been discussed with Delivery Team?

Description of work

Implementation of detail player on film detail page

Config settings/Toggles required for the feature to work

  • use_detail_page_player = true adds player to film detail page

Affected Clients

  • All clients who use Kibble

Checklist

  • CI tests are passing Github actions (inc. linting)
  • Key areas of the feature outlined for context and testing
  • If there are designs for this work are they noted here and in the ADO card
  • Design review
  • Have checked this at multiple screen resolutions and range of browsers
  • Moved ADO card to Dev/done, checked link to Github, tagged "Review"
  • Updated changelog (if applicable)
  • I promise to document any new feature toggles/configurations in the appropriate documentation

{{showPricingButtons := isFilm || isSeason || isBundle}}

{{showPlayButton := isFilm || isSeason || isEpisode}}
{{showPlayButton := isFilm || isSeason || isEpisode && config("is_creator", "false") == "false" }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This config should be more specific about what it does, e.g. use_detail_page_player because we might want to use this on non-creator sites.

container.classList[action]('detail-player-theatre-mode');
container.querySelector('detail-player').scrollIntoView({ behavior: 'smooth', block: 'start' });
document.querySelector('.meta-detail-bg').classList[action]('meta-detail-bg--lights-out');
document.querySelector('.poster-wrapper').classList[action]('d-none');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The toggle method on classList does this: el.classList.toggle('detail-player-theatre-mode', isTheatreMode)

});
window.addEventListener('message', e => {
if (e.data.event == 's72-checkout:close') {
if (element.classList.contains('try-unlock')) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's usually better to use component state rather than DOM elements as the source of truth for a React component.

Using component state means that any changes will queue up a re-render, if necessary, and the render function tells the framework how it wants the DOM to look.

It seems to me that when the shopping session completed event occurs, it should retrigger the same logic to set canBeWatched and maybe a purchaseCompleted flag, and then in the render it can add the appropriate classes to the DOM elements to trigger animations.

Was there a reason it was necessary to bypass component renders here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I have no idea why I did this instead of using state

Copy link
Contributor

@sam-shift72 sam-shift72 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. I see the CSS still refers to it as meta-detail-creator but perhaps that's fine until the paint dries on the detail player, comments etc.

getCanBeWatched(callback) {
this.app.availabilityService.getAvailability(this.props.slug).then(a => {
if (a) { callback(a.canBeWatched) }
});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is okay, but it would be nicer to stay "inside" the promise, e.g.

canBeWatched() {
  return this.app.availabilityService.getAvailability(this.props.slug)
    .then(a => a?.canBeWatched ?? false)
    .catch(() => false)
}

componentDidMount() {
  bus.subscribe(..., async () => {
    if (await this.canBeWatched()) {
      this.setState(...)
    }
  });
}

Caveat: I only recently upgraded core-template from using the old buble compiler to babel to get support for modern JS features, but optional chaining (?., ??) and async/await can make this kind of code much simpler

);
}

playIcon() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I mentioned this in the Relish PR but it would be more idiomatic React to refactor these to be separate components rather than render-functions. Its not a big deal though and it's an easy tidy up later.

documentReady(app);
});

window.addEventListener('message', e => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be added to the componentDidMount of the detail player component instead? That would keep the code together.

Even if we were building a proper SPA we'd add this event listener when the detail player mounts, and then unsubscribe in componentDidUnmount, but our Relish components are all sloppy about that

{{showPricingButtons := isFilm || isSeason || isBundle}}

{{showPlayButton := isFilm || isSeason || isEpisode}}
{{showPlayButton := isFilm || isSeason || isEpisode && config("use_detail_page_player", "false") == "false" }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's best to add parens to conditions like this to communicate which of these you mean:

  1. isFilm || isSeason || (isEpisode && !useDetailPlayer)
  2. (isFilm || isSeason || isEpisode) && !useDetailPlayer

I don't know the intricacies of CloudyKit Jet's parser, but in most languages && has higher precedence over ||, so the code as written is case 1 ("only show the play button for episodes if we're not using detail player")

Adding a variable like {{useDetailPlayer := config(...) == "true" }} and will help make it more readable too.

@sam-shift72 sam-shift72 requested a review from l0ud0gg July 1, 2025 01:31
Copy link
Contributor

@sam-shift72 sam-shift72 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added @l0ud0gg to get his thoughts but I think this nearly looks good to merge.

@@ -1,8 +1,8 @@
{{block filmTitle(title,class,element="h1")}}
{{block filmTitle(title, class, element = "h1", forceText = false)}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not immediately obvious what forceText means. Perhaps this parameter should be useTitleImage = true and then it can be useTitleImage=!useDetailPlayer when invoking the block

{{showPlayButton := isFilm || isSeason || isEpisode}}
{{useDetailPlayer := config("use_detail_page_player", "false") == "true"}}

{{showPlayButton := (isFilm || isSeason || isEpisode) && !useDetailPlayer }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the detail player is enabled, this gets rid of the play CTA from carousel items which isn't desirable. Maybe this should be && (isCarousel || !useDetailPlayer)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah good catch

Copy link
Contributor

@l0ud0gg l0ud0gg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks good as man. just left one comment on a edge case but i think we can just write a basic wiki page outlining the feature and that it requires that config if need be.

>
{this.placeholderBG()}
<div class="detail-player-placeholder-overlay">
{state.canBeWatched && this.playButton() }
Copy link
Contributor

@l0ud0gg l0ud0gg Jul 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We found a bug here when a site does not have the "disable_anonymous_watch_now" meta config set. It will display a play button for anonymous users and if clicked will open the sign in page within the detail player iframe. For now its prolly fine as we can ensure this config is a prereq for this feature, but might do some wierd things otherwise for other business models.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah there are a bunch of edge cases that still need to be sorted with this feature before it's ready for widespread deployment but I don't think they're blockers for merge.

@sam-shift72
Copy link
Contributor

i did a little bit of side-by-side regression testing on tvoddemo (with this feature disabled) and I didn't notice any responsive layout issues so should be safe to merge from that pov

@flyspraysandwich flyspraysandwich merged commit 45f4b62 into develop Jul 1, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants