Skip to content

Commit

Permalink
Merge pull request #182 from devgeniem/TMS-1052
Browse files Browse the repository at this point in the history
TMS-1052: Favorite programs
  • Loading branch information
eebbi authored Sep 3, 2024
2 parents 93658d3 + 9541fb0 commit 7016403
Show file tree
Hide file tree
Showing 20 changed files with 709 additions and 196 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

- TMS-1052: Favorite programs-functionalities
- TMS-1051: Add "Print page"-button to single program

## [1.8.17] - 2024-08-21
Expand Down
288 changes: 288 additions & 0 deletions assets/scripts/program-favorite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
/* eslint-disable no-console */
/**
* Favorites-functionality for programs.
*/

// Use jQuery as $ within this file scope.
const $ = jQuery;

/**
* Class FavoritePrograms
*/
export default class FavoritePrograms {
/**
* Execute on page load
*/
docReady() {
// Bail if browser does not support localStorage.
if ( typeof Storage === 'undefined' ) {
return;
}

this.cache();
this.favorites = this.parseFavorites();

if ( ! this.hasFavorites() ) {
this.showNoResults();
}

// Init functionalities common to all templates.
this.initCommon();

// Init functionalities for favorite-listing.
this.initFavorites();

// Favorite popup functionalities
this.favoritePopup();
}

/**
* Cache selectors
*/
cache() {
this.classes = {
hasFavorites: 'has-favorites',
isFavorite: 'is-favorite',
hide: 'is-hidden',
};

this.selectors = {
button: '.js-toggle-favorite',
};
this.storageKey = 'tredu-program-favorites';
this.closeFavorites = $( '#js-favorites-close' );
this.openFavorites = $( '#js-favorites-open' );
this.favoritesContainer = $( '#js-favorites-container' );
this.favoritePrograms = $( '#js-favorite-programs' );
this.favoritesContent = $( '#js-favorites-content' );
this.favoritesNoResults = $( '#js-favorites-no-results' );
}

/**
* Initialize functionalities common for all templates.
*/
initCommon() {
this.favoriteButtons = $( this.selectors.button );

if ( this.favoriteButtons.length > 0 ) {
this.populateFavorites();
}
}

/**
* Initialize functionalities for favorites listing.
*/
initFavorites() {
// Fetch favorites according to localStorage.
if ( this.favorites.length !== 0 ) {
dp( 'ProgramFavorites/FavoritePrograms', {
partial: 'header-favorites-item',
tidy: true,
data: true,
args: {
ids: this.favorites,
},
} ).then( ( response ) => {
if ( ! response.success ) {
this.showNoResults();
return;
}

// Set favorites content.
this.favoritePrograms.html( response.success );

// Show the container.
this.favoritePrograms.removeClass( this.classes.hide );
} ).catch( ( error ) => {
console.log( error );
this.showNoResults();
} );
}

// Update favorites when favorite-button clicked
if ( this.favoritesContainer.length > 0 ) {
this.favoriteButtons.on( 'click', ( e ) => {
e.stopPropagation();
this.toggleFavorite( e.currentTarget );
this.loadFavorites();
} );

$( document ).on( 'click', '.js-remove-favorite', ( e ) => {
e.stopPropagation();
this.removeFavorite( e.currentTarget );
this.loadFavorites();
} );
}
}

/**
* Update favorite popup button attributes.
*/
favoritePopup() {
this.closeFavorites.on( 'click', ( e ) => {
e.stopPropagation();
this.openFavorites.attr( 'aria-expanded', 'false' );
this.openFavorites.removeClass( 'is-active' );
} );
}

/**
* Parse favorite programs from localStorage.
*
* @return {Array} The localStorage values or an empty array.
*/
parseFavorites() {
const favorites = localStorage.getItem( this.storageKey );

if ( ! favorites ) {
return [];
}

return JSON.parse( favorites );
}

/**
* Save passed favorites to localStorage.
*
* @param {Array} favorites The favorites as array
*/
saveFavorites( favorites = [] ) {
localStorage.setItem( this.storageKey, JSON.stringify( favorites ) );
}

/**
* Populate favorites from localStorage.
*
* @return {void}
*/
populateFavorites() {
// Loop over the favorite buttons and update their favorite-status.
for ( const item of this.favoriteButtons ) {
const programId = $( item ).data( 'program-id' );

if ( this.favorites.includes( programId ) ) {
$( item ).addClass( this.classes.isFavorite );
$( item ).attr( 'aria-pressed', 'true' );
$( item ).find( '.text-favorite-active' ).removeClass( this.classes.hide );
$( item ).find( '.text-favorite-inactive' ).addClass( this.classes.hide );
}
}
}

/**
* Check if there are favorites in the localStorage.
*
* @return {boolean} True if favorites exist.
*/
hasFavorites() {
return this.favorites.length > 0;
}

/**
* Changes favorite-status of the selected favorite.
*
* @param {Element} selectedItem The button element to be toggled.
* @return {void}
*/
toggleFavorite( selectedItem ) {
const programId = $( selectedItem ).data( 'program-id' );

// Add or remove program ID from localStorage.
if ( this.favorites.includes( programId ) ) {
this.favorites = this.favorites.filter( ( fav ) => fav !== programId );
$( selectedItem ).removeClass( this.classes.isFavorite );
$( selectedItem ).find( '.text-favorite-active' ).addClass( this.classes.hide );
$( selectedItem ).find( '.text-favorite-inactive' ).removeClass( this.classes.hide );
$( selectedItem ).attr( 'aria-pressed', 'false' );
}
else {
this.favorites.push( programId );
$( selectedItem ).addClass( this.classes.isFavorite );
$( selectedItem ).find( '.text-favorite-active' ).removeClass( this.classes.hide );
$( selectedItem ).find( '.text-favorite-inactive' ).addClass( this.classes.hide );
$( selectedItem ).attr( 'aria-pressed', 'true' );
}

// Save to localStorage.
this.saveFavorites( this.favorites );
}

/**
* Remove favorite.
*
* @param {Element} selectedItem The button element to be toggled.
* @return {void}
*/
removeFavorite( selectedItem ) {
const programId = $( selectedItem ).data( 'program-id' );

// Remove program ID from localStorage.
if ( this.favorites.includes( programId ) ) {
this.favorites = this.favorites.filter( ( fav ) => fav !== programId );
this.toggleFavoriteButton = $( '.js-toggle-favorite[data-program-id="' + programId + '"]' );

// Remove toggle-buttons attributes and texts
if ( this.toggleFavoriteButton.length > 0 ) {
this.toggleFavoriteButton.removeClass( this.classes.isFavorite );
this.toggleFavoriteButton.attr( 'aria-pressed', 'false' );
this.toggleFavoriteButton.find( '.text-favorite-active' ).addClass( this.classes.hide );
this.toggleFavoriteButton.find( '.text-favorite-inactive' ).removeClass( this.classes.hide );
}
}

// Save to localStorage.
this.saveFavorites( this.favorites );
}

/**
* Show "no results" content.
*/
showNoResults() {
this.favoritesContent.addClass( this.classes.hide );
this.favoritesNoResults.removeClass( this.classes.hide );
}

/**
* Hide "no results" content.
*/
hideNoResults() {
this.favoritesContent.removeClass( this.classes.hide );
this.favoritesNoResults.addClass( this.classes.hide );
}

/**
* Load and show the favorite programs.
*
* @return {void}
*/
loadFavorites() {
// Fetch favorites according to localStorage.
dp( 'ProgramFavorites/FavoritePrograms', {
partial: 'header-favorites-item',
tidy: true,
data: true,
args: {
ids: this.favorites,
},
} ).then( ( response ) => {
if ( ! response.success ) {
this.showNoResults();
}
else {
this.hideNoResults();
}

// Set favorites content.
this.favoritePrograms.html( response.success );

// Refresh favorite buttons and add event listeners.
this.initCommon();

// Show the container.
this.favoritePrograms.removeClass( this.classes.hide );
} ).catch( () => {
this.showNoResults();
} );
}

}
2 changes: 2 additions & 0 deletions assets/scripts/theme.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import ProgramSearch from './program-search';
import LoadMore from './load-more';
import SearchFilters from './search-filters';
import FocusOnSearch from './focus-on-search';
import FavoritePrograms from './program-favorite';

const globalControllers = {
Common,
Expand Down Expand Up @@ -59,6 +60,7 @@ const globalControllers = {
LoadMore,
SearchFilters,
FocusOnSearch,
FavoritePrograms,
};

const templateControllers = {
Expand Down
45 changes: 45 additions & 0 deletions assets/styles/ui-components/header/_header-favorites.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#js-favorites-open {
flex: 1 0 auto;
width: 2.375rem;
height: 2.375rem;

svg {
margin: 0 !important;
}

@include from($tablet) {
width: rem(50px);
height: rem(50px);
}
}

#js-favorites-container {
ul {
list-style: none;
padding: 0;

li {
&:not(:last-of-type) {
border-bottom: 2px solid $primary;
}

.button-container {
display: flex;
gap: $theme-spacing-two;

.button.js-remove-favorite {
padding: 0;
background-color: transparent;
border-color: transparent;

svg.icon {
margin-left: .25rem !important;
margin-right: 0 !important;
height: 1.25rem;
width: 1.25rem;
}
}
}
}
}
}
5 changes: 2 additions & 3 deletions assets/styles/ui-components/header/_language-nav.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
.lang-nav {
.dropdown-menu {
z-index: 25;

}

&--horizontal {
Expand All @@ -16,8 +15,8 @@
height: 2.375rem;

@include from($tablet) {
width: rem(50);
height: rem(50);
width: rem(50px);
height: rem(50px);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions assets/styles/ui-components/index.scss
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
@import "header/header-favorites";
@import "header/header-top";
@import "header/bulmally-navbar";
@import "header/primary-nav";
Expand Down
Loading

0 comments on commit 7016403

Please sign in to comment.