Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TMS-1052: Favorite programs #182

Merged
merged 5 commits into from
Sep 3, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

- TMS-1052: Favorite programs-functionalities

## [1.8.16] - 2024-06-26

- TMS-925:
Expand Down
280 changes: 280 additions & 0 deletions assets/scripts/program-favorite.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
/* eslint-disable no-console */
/**
* Load more functionality for koulutusnosto-component.
Copy link
Contributor

Choose a reason for hiding this comment

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

Väärä kommentti

*/

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

/**
* Class LoadMore
Copy link
Contributor

Choose a reason for hiding this comment

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

Väärä kommentti

*/
export default class FavoritePrograms {
docReady() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Näille parille metodille vois heittää docblock-kommentin vielä

// 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() {
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 );
Copy link
Contributor

Choose a reason for hiding this comment

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

Kaikki luokan variablejen asetukset kannattaisi olla tossa cache metodissa.


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 ) => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Voisiko tällä classilla tehdä myös jonkun this.removeFavoriteButtonsin ja tehdä event listenerin samalla tavalla kuin tossa yllä?

Copy link
Contributor Author

@eebbi eebbi Aug 28, 2024

Choose a reason for hiding this comment

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

Piti toteuttaa tälleen, koska .js-remove-favorite painikkeet tulee dynaamisesti listaukseen yksittäisen suosikki-itemin mukana

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 {Object} selectedItem The button element to be toggled.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* @param {Object} selectedItem The button element to be toggled.
* @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 {Object} selectedItem The button element to be toggled.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* @param {Object} selectedItem The button element to be toggled.
* @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 + '"]' );
Copy link
Contributor

Choose a reason for hiding this comment

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

Pitäiskö tässä tsekata, että elementti varmasti löytyy, koska on aika monimutkainen selector? Tässä voisi varmaan vetää returnin, jos elementtiä ei ole olemassa, muuten tulee consoleen virheitä.


// Remove toggle-buttons attributes and texts
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: 2rem;
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
gap: 2rem;
gap: $theme-spacing-two;

Olihan täällä noi spacing-muuttujat?


.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