Refractor Search to TS (#1373)

This commit is contained in:
Ignacio Bona Piedrabuena 2018-09-11 11:11:36 -07:00 committed by GitHub
parent 141ae826bc
commit ca7110ea11
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 199 additions and 154 deletions

View File

@ -1,75 +1,9 @@
import Controller from '@ember/controller';
import { computed, set, get } from '@ember/object';
import { capitalize } from '@ember/string';
import { action } from '@ember-decorators/object';
import { set } from '@ember/object';
import { action, computed } from '@ember-decorators/object';
// gradual refactor into es class, hence extends EmberObject instance
export default class Search extends Controller.extend({
isMetrics: computed('model.category', function() {
var model = this.get('model');
if (model && model.category) {
if (model.category.toLocaleLowerCase() === 'metrics') {
return true;
}
}
return false;
}),
previousPage: computed('model.page', function() {
var model = this.get('model');
if (model && model.page) {
var currentPage = model.page;
if (currentPage <= 1) {
return currentPage;
} else {
return currentPage - 1;
}
} else {
return 1;
}
}),
nextPage: computed('model.page', function() {
var model = this.get('model');
if (model && model.page) {
var currentPage = model.page;
var totalPages = model.totalPages;
if (currentPage >= totalPages) {
return totalPages;
} else {
return currentPage + 1;
}
} else {
return 1;
}
}),
first: computed('model.page', function() {
var model = this.get('model');
if (model && model.page) {
var currentPage = model.page;
if (currentPage <= 1) {
return true;
} else {
return false;
}
} else {
return false;
}
}),
last: computed('model.page', function() {
var model = this.get('model');
if (model && model.page) {
var currentPage = model.page;
var totalPages = model.totalPages;
if (currentPage >= totalPages) {
return true;
} else {
return false;
}
} else {
return false;
}
})
}) {
export default class SearchController extends Controller {
queryParams = ['keyword', 'category', 'source', 'page'];
/**
@ -107,7 +41,80 @@ export default class Search extends Controller.extend({
* @param source
*/
@action
sourceDidChange(source) {
sourceDidChange(source: string) {
set(this, 'source', source);
}
@computed('model.category')
get isMetrics(): boolean {
const model = this.get('model');
if (model && model.category) {
if (model.category.toLocaleLowerCase() === 'metrics') {
return true;
}
}
return false;
}
@computed('model.page')
get previousPage(): number {
const model = this.get('model');
if (model && model.page) {
var currentPage = model.page;
if (currentPage <= 1) {
return currentPage;
} else {
return currentPage - 1;
}
} else {
return 1;
}
}
@computed('model.page')
get nextPage(): number {
const model = this.get('model');
if (model && model.page) {
const currentPage = model.page;
const totalPages = model.totalPages;
if (currentPage >= totalPages) {
return totalPages;
} else {
return currentPage + 1;
}
} else {
return 1;
}
}
@computed('model.page')
get first(): boolean {
const model = this.get('model');
if (model && model.page) {
const currentPage = model.page;
if (currentPage <= 1) {
return true;
} else {
return false;
}
} else {
return false;
}
}
@computed('model.page')
get last(): boolean {
const model = this.get('model');
if (model && model.page) {
const currentPage = model.page;
const totalPages = model.totalPages;
if (currentPage >= totalPages) {
return true;
} else {
return false;
}
} else {
return false;
}
}
}

View File

@ -1,61 +0,0 @@
import Route from '@ember/routing/route';
import { isBlank } from '@ember/utils';
import $ from 'jquery';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
import buildUrl from 'wherehows-web/utils/build-url';
import createSearchEntries from 'wherehows-web/utils/datasets/create-search-entries';
const queryParams = ['keyword', 'category', 'page', 'source'];
// TODO: DSS-6581 Create URL retrieval module
const urlRoot = '/api/v1/search';
export default Route.extend(AuthenticatedRouteMixin, {
// Set `refreshModel` for each queryParam to true
// so each url state change results in a full transition
queryParams: queryParams.reduce((queryParams, param) => {
queryParams[param] = { refreshModel: true };
return queryParams;
}, {}),
/**
* Applies the returned results object as the route model and sets
* keyword property on the route controller
* @param {Object} controller search route controller
* @param {Object} model search results
*/
setupController(controller, model) {
const { keywords } = model;
controller.setProperties({
model,
keyword: keywords
});
},
/**
*
* @param params
*/
model(params = {}) {
const searchUrl = queryParams.reduce((url, queryParam) => {
const queryValue = params[queryParam];
if (!isBlank(queryValue)) {
return buildUrl(url, queryParam, queryValue);
}
return url;
}, urlRoot);
return Promise.resolve($.getJSON(searchUrl)).then(({ status, result }) => {
if (status === 'ok') {
const { keywords, data } = result;
createSearchEntries(data, keywords);
return result;
}
return Promise.reject(new Error(`Request for ${searchUrl} failed with: ${status}`));
});
}
});

View File

@ -0,0 +1,37 @@
import Route from '@ember/routing/route';
import AuthenticatedRouteMixin from 'ember-simple-auth/mixins/authenticated-route-mixin';
import createSearchEntries from 'wherehows-web/utils/datasets/create-search-entries';
import { refreshModelQueryParams } from 'wherehows-web/utils/helpers/routes';
import SearchController from 'wherehows-web/controllers/search';
import { readSearch, ISearchApiParams } from 'wherehows-web/utils/api/search';
export default class SearchRoute extends Route.extend(AuthenticatedRouteMixin) {
// Set `refreshModel` for each queryParam to true
// so each url state change results in a full transition
queryParams = refreshModelQueryParams(['keyword', 'category', 'page', 'source']);
/**
* Applies the returned results object as the route model and sets
* keyword property on the route controller
* @param {Object} controller search route controller
* @param {Object} model search results
*/
setupController(controller: SearchController, model: any) {
const { keywords } = model;
controller.setProperties({
model,
keyword: keywords
});
}
/**
* Makes an API call and process search entries
*/
async model(apiParams: ISearchApiParams) {
const { result } = await readSearch(apiParams);
const { keywords, data } = result;
createSearchEntries(data, keywords);
return result;
}
}

View File

@ -0,0 +1,23 @@
import { getApiRoot, ApiStatus } from 'wherehows-web/utils/api/shared';
import buildUrl from 'wherehows-web/utils/build-url';
import { getJSON } from 'wherehows-web/utils/api/fetcher';
export interface ISearchApiParams {
keyword: string;
category: string;
source: string;
page: number;
[key: string]: any;
}
export interface ISearchResponse {
status: ApiStatus;
result: {
keywords: string;
data: Array<any>;
};
}
export const searchUrl = (params: ISearchApiParams): string => buildUrl(`${getApiRoot()}/search`, params);
export const readSearch = (params: ISearchApiParams) => getJSON<ISearchResponse>({ url: searchUrl(params) });

View File

@ -1,4 +1,5 @@
import { encode, decode } from 'wherehows-web/utils/encode-decode-uri-component-with-space';
import { isBlank } from '@ember/utils';
/**
* Construct a url by appending a query pair (?key=value | &key=value) to a base url and
@ -8,34 +9,56 @@ import { encode, decode } from 'wherehows-web/utils/encode-decode-uri-component-
* @param {String} queryValue
* @returns {string}
*/
export default (baseUrl: string, queryParam: string, queryValue: string): string => {
function buildUrl(): string;
function buildUrl(baseUrl: string, mapParams: Record<string, any>): string;
function buildUrl(baseUrl: string, queryKey: string, queryValue: string): string;
function buildUrl(baseUrl?: string, queryParamOrMap?: string | Record<string, string>, queryValue?: string): string {
if (!baseUrl) {
return '';
}
if (!queryParam) {
if (!queryParamOrMap) {
return baseUrl;
}
// If the query string already contains the initial question mark append
// kv-pair with ampersand
const separator = String(baseUrl).includes('?') ? '&' : '?';
// Malformed URL will cause decodeURIComponent to throw
// handle and encode queryValue in such instance
try {
// Check if queryValue is already encoded,
// otherwise encode queryValue before composing url
// e.g. if user directly enters query in location bar
if (decode(queryValue) === queryValue) {
queryValue = encode(queryValue);
}
} catch (err) {
if (err instanceof URIError) {
queryValue = encode(queryValue);
}
throw err;
let paramMap: { [x: string]: string };
if (typeof queryParamOrMap === 'string') {
paramMap = {
[queryParamOrMap]: queryValue || ''
};
} else {
paramMap = queryParamOrMap;
}
return `${baseUrl}${separator}${queryParam}=${queryValue}`;
};
return Object.keys(paramMap).reduce((url, paramKey) => {
// If the query string already contains the initial question mark append
// kv-pair with ampersand
const separator = String(url).includes('?') ? '&' : '?';
let paramValue = paramMap[paramKey];
if (isBlank(paramValue)) {
return url;
}
// Malformed URL will cause decodeURIComponent to throw
// handle and encode queryValue in such instance
try {
// Check if queryValue is already encoded,
// otherwise encode queryValue before composing url
// e.g. if user directly enters query in location bar
if (decode(paramValue) === queryValue) {
paramValue = encode(paramValue);
}
} catch (err) {
if (err instanceof URIError) {
paramValue = encode(paramValue);
}
throw err;
}
return `${url}${separator}${paramKey}=${paramValue}`;
}, baseUrl);
}
export default buildUrl;

View File

@ -8,7 +8,7 @@ module('Unit | Utility | build url', function() {
let result = buildUrl();
assert.equal(result, '', 'returns an empty string when no arguments are passed');
result = buildUrl(baseUrl, '');
result = buildUrl(baseUrl, '', '');
assert.equal(result, baseUrl, 'returns the baseUrl when no query parameter is supplied');
result = buildUrl(baseUrl, 'search', 'text');
@ -16,5 +16,21 @@ module('Unit | Utility | build url', function() {
result = buildUrl(result, 'query', 'text2');
assert.equal(result, `${baseUrl}?search=text&query=text2`);
result = buildUrl(baseUrl, {
keyName1: 'keyValue1',
keyName2: 2,
keyName3: true
});
assert.equal(result, `${baseUrl}?keyName1=keyValue1&keyName2=2&keyName3=true`);
result = buildUrl(baseUrl, {
keyName1: 0,
keyName3: undefined,
keyName4: '',
keyName5: null,
keyName2: false
});
assert.equal(result, `${baseUrl}?keyName1=0&keyName2=false`);
});
});