Skip to content

Commit

Permalink
Switch favorites to use Algolia search
Browse files Browse the repository at this point in the history
  • Loading branch information
NuckChorris committed Jun 18, 2022
1 parent 291e19c commit 9719c42
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 49 deletions.
94 changes: 68 additions & 26 deletions app/components/users/edit-profile/body/favorites/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,43 @@ import Component from '@ember/component';
import { get, set, computed } from '@ember/object';
import { inject as service } from '@ember/service';
import { capitalize } from '@ember/string';
import { isEmpty } from '@ember/utils';
import { task, timeout } from 'ember-concurrency';
import { strictInvokeAction } from 'ember-invoke-action';
import { concat } from 'client/utils/computed-macros';
import Pagination from 'kitsu-shared/mixins/pagination';

const ALGOLIA_INDICES = {
character: {
index: 'characters',
fields: ['id', 'slug', 'canonicalName', 'image']
},
anime: {
index: 'media',
fields: ['id', 'slug', 'canonicalTitle'],
filters: 'kind:anime'
},
manga: {
index: 'media',
fields: ['id', 'slug', 'canonicalTitle'],
filters: 'kind:manga'
}
};

export default Component.extend(Pagination, {
algolia: service(),
store: service(),
favorites: concat('getFavoritesTask.lastSuccessful.value', 'paginatedRecords'),
filteredFavorites: computed('favorites.@each.{isDeleted,favRank}', function() {
return get(this, 'favorites').rejectBy('isDeleted').sortBy('favRank');
}).readOnly(),

favorites: concat(
'getFavoritesTask.lastSuccessful.value',
'paginatedRecords'
),
filteredFavorites: computed(
'favorites.@each.{isDeleted,favRank}',
function () {
return get(this, 'favorites').rejectBy('isDeleted').sortBy('favRank');
}
).readOnly(),

init() {
this._super(...arguments);
Expand All @@ -32,8 +58,8 @@ export default Component.extend(Pagination, {
sort: 'fav_rank',
page: { limit: 20 }
};
return yield this.queryPaginated('favorite', options).then(records => {
records.forEach(record => {
return yield this.queryPaginated('favorite', options).then((records) => {
records.forEach((record) => {
strictInvokeAction(this, 'addRecord', record);
});
return records;
Expand All @@ -42,51 +68,67 @@ export default Component.extend(Pagination, {

searchTask: task(function* (query) {
yield timeout(200);
const field = get(this, 'isCharacter') ? 'name' : 'text';
const type = get(this, 'type');
return yield get(this, 'store').query(type, {
filter: { [field]: query },
fields: this._getFieldsets(type),
page: { limit: 6 }
}).then(records => records.reject(record => (
get(this, 'favorites').map(favorite => get(favorite, 'item.id')).includes(get(record, 'id'))
)));
const indexInfo = ALGOLIA_INDICES[get(this, 'type')];
const index = yield this.get('algolia.getIndex').perform(indexInfo.index);
if (isEmpty(index) || isEmpty(query)) {
return [];
}
const response = yield index.search(query, {
filters: indexInfo.filters,
attributesToRetrieve: indexInfo.fields,
attributesToHighlight: [],
queryLanguages: ['en', 'ja'],
naturalLanguages: ['en', 'ja'],
hitsPerPage: 20,
responseFields: ['hits'],
removeStopWords: false,
removeWordsIfNoResults: 'allOptional'
});
return response.hits;
}).restartable(),

onPagination(records) {
this._super(records);
records.forEach(record => {
records.forEach((record) => {
strictInvokeAction(this, 'addRecord', record);
});
},

actions: {
reorderItems(orderedItems) {
orderedItems.forEach(item => set(item, 'favRank', orderedItems.indexOf(item) + 1));
orderedItems.forEach((item) =>
set(item, 'favRank', orderedItems.indexOf(item) + 1)
);
},

addFavorite(item) {
const record = get(this, 'store').createRecord('favorite', {
user: get(this, 'session.account'),
item
this.store.findRecord(this.get('type'), item.id).then((itemRecord) => {
const record = get(this, 'store').createRecord('favorite', {
user: get(this, 'session.account'),
item: itemRecord
});
get(this, 'paginatedRecords').addObject(record);
strictInvokeAction(this, 'addRecord', record);
// @TODO: Should be moved to adapter level
get(this, 'session.account').incrementProperty('favoritesCount');
});
get(this, 'paginatedRecords').addObject(record);
strictInvokeAction(this, 'addRecord', record);
// @TODO: Should be moved to adapter level
get(this, 'session.account').incrementProperty('favoritesCount');
},

removeFavorite(favorite) {
favorite.deleteRecord();
const favorites = get(this, 'filteredFavorites');
favorites.forEach(item => set(item, 'favRank', favorites.indexOf(item) + 1));
favorites.forEach((item) =>
set(item, 'favRank', favorites.indexOf(item) + 1)
);
}
},

_getFieldsets(type) {
if (type === 'character') {
return { characters: ['name', 'image'].join(',') };
}
return { [type]: ['slug', 'posterImage', 'canonicalTitle', 'titles'].join(',') };
return {
[type]: ['slug', 'posterImage', 'canonicalTitle', 'titles'].join(',')
};
}
});
70 changes: 47 additions & 23 deletions app/templates/components/users/edit-profile/body/favorites/list.hbs
Original file line number Diff line number Diff line change
@@ -1,60 +1,84 @@
<div class="favorite-search m-t-2 m-b-2">
<div class='favorite-search m-t-2 m-b-2'>
{{#power-select
search=(perform searchTask)
onchange=(action "addFavorite")
onchange=(action 'addFavorite')
renderInPlace=true
as |item|}}
as |item|
}}
{{#if isCharacter}}
<span class="waifu-wrapper">
<span class='waifu-wrapper'>
{{lazy-image src=(image item.image)}}
</span>
<strong>{{item.name}}</strong>
<strong>{{item.canonicalName}}</strong>
{{else}}
<strong>{{item.computedTitle}}</strong>
<strong>{{item.canonicalTitle}}</strong>
{{/if}}
{{/power-select}}
</div>

{{#if getFavoritesTask.last.isRunning}}
<div class="text-xs-center w-100 m-b-2 m-t-2">
{{loading-spinner size="large"}}
<div class='text-xs-center w-100 m-b-2 m-t-2'>
{{loading-spinner size='large'}}
</div>
{{else if getFavoritesTask.last.error}}
<div class="text-xs-center w-100 m-b-2 m-t-2">
{{t "errors.load"}}
<div class='text-xs-center w-100 m-b-2 m-t-2'>
{{t 'errors.load'}}
</div>
{{else if filteredFavorites}}
{{#infinite-pagination onPagination=(action "onPagination")}}
{{#sortable-group tagName="ul" class="media-sortable nav" onChange=(action "reorderItems") as |group|}}
{{#infinite-pagination onPagination=(action 'onPagination')}}
{{#sortable-group
tagName='ul'
class='media-sortable nav'
onChange=(action 'reorderItems')
as |group|
}}
{{#each filteredFavorites as |favorite|}}
{{#sortable-item model=favorite group=group tagName="li" class="media-sort-item card"}}
{{#sortable-item
model=favorite
group=group
tagName='li'
class='media-sort-item card'
}}
{{#if isCharacter}}
<a class="media-sort-thumb-wrapper" href="#">
{{lazy-image src=(image favorite.item.image) class="media-sort-thumb"}}
<a class='media-sort-thumb-wrapper' href='#'>
{{lazy-image
src=(image favorite.item.image)
class='media-sort-thumb'
}}
</a>
{{else}}
<a class="media-sort-thumb-wrapper" href={{href-to (concat type ".show") favorite.item.slug}}>
{{lazy-image src=(image favorite.item.posterImage "tiny") class="media-sort-thumb"}}
<a
class='media-sort-thumb-wrapper'
href={{href-to (concat type '.show') favorite.item.slug}}
>
{{lazy-image
src=(image favorite.item.posterImage 'tiny')
class='media-sort-thumb'
}}
</a>
{{/if}}
<span class="media-sort-title">
<span class='media-sort-title'>
{{#if isCharacter}}
{{favorite.item.name}}
{{else}}
{{favorite.item.computedTitle}}
{{/if}}
</span>
<span class="media-sort-action">
<a class="hint--left hint--bounce hint--rounded" aria-label={{t "users.edit-modal.favorites.remove"}} {{action "removeFavorite" favorite}}>
{{svg-jar "cancel"}}
<span class='media-sort-action'>
<a
class='hint--left hint--bounce hint--rounded'
aria-label={{t 'users.edit-modal.favorites.remove'}}
{{action 'removeFavorite' favorite}}
>
{{svg-jar 'cancel'}}
</a>
</span>
{{/sortable-item}}
{{/each}}
{{/sortable-group}}
{{/infinite-pagination}}
{{else}}
<div class="text-xs-center w-100 m-b-2 m-t-2">
{{t "errors.contentEmpty"}}
<div class='text-xs-center w-100 m-b-2 m-t-2'>
{{t 'errors.contentEmpty'}}
</div>
{{/if}}

0 comments on commit 9719c42

Please sign in to comment.