diff --git a/.vscode/settings.json b/.vscode/settings.json index f3fba92a..7cc8a413 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,7 @@ { "editor.tabSize": 2, "editor.formatOnSave": true, + "editor.rulers": [100], "[css]": { "editor.defaultFormatter": "esbenp.prettier-vscode" }, diff --git a/app/components/essentia/boost.tsx b/app/components/essentia/boost.tsx index d2008ba6..65b211f3 100644 --- a/app/components/essentia/boost.tsx +++ b/app/components/essentia/boost.tsx @@ -5,7 +5,6 @@ import EmpireRPCStore from 'app/stores/rpc/empire'; import * as util from 'app/util'; import Icon from 'app/components/menu/icon'; import { IconStyle } from 'app/interfaces/menu/icons'; -import EmpireService from 'app/services/empire'; import { int } from 'app/util'; type Props = { @@ -24,7 +23,7 @@ class Boost extends React.Component { console.log(`Boosting ${type} for ${weeks} weeks`); - EmpireService.setBoost(type, weeks); + // TODO - use the lacuna client to do this } tagClassNames() { diff --git a/app/components/essentia/boostsTab.tsx b/app/components/essentia/boostsTab.tsx index b68ca591..86996163 100644 --- a/app/components/essentia/boostsTab.tsx +++ b/app/components/essentia/boostsTab.tsx @@ -2,13 +2,16 @@ import React from 'react'; import { observer } from 'mobx-react'; import EmpireRPCStore from 'app/stores/rpc/empire'; import BoostsRPCStore from 'app/stores/rpc/empire/boosts'; -import EmpireService from 'app/services/empire'; +import lacuna from 'app/lacuna'; import Boost from 'app/components/essentia/boost'; class BoostsTab extends React.Component { - componentDidMount() { - EmpireService.getBoosts(); + async componentDidMount() { + const { result } = await lacuna.empire.viewBoosts(); + if (result) { + BoostsRPCStore.update(result); + } } render() { diff --git a/app/components/invite.tsx b/app/components/invite.tsx index aae71b2a..2c32fce8 100644 --- a/app/components/invite.tsx +++ b/app/components/invite.tsx @@ -1,22 +1,31 @@ import React from 'react'; import { observer } from 'mobx-react'; import InviteRPCStore from 'app/stores/rpc/empire/invite'; -import EmpireService from 'app/services/empire'; +import lacuna from 'app/lacuna'; +import * as vex from 'app/vex'; class InviteWindow extends React.Component { emailInput = React.createRef(); messageInput = React.createRef(); - componentDidMount() { - EmpireService.getInviteFriendUrl(); + async componentDidMount() { + const { result } = await lacuna.empire.getInviteFriendUrl(); + if (result) { + InviteRPCStore.update(result); + } } - handleInvite() { + async handleInvite() { if (this.emailInput.current && this.messageInput.current) { const email = this.emailInput.current.value; const message = this.messageInput.current.value; - EmpireService.inviteFriend(email, message); + const { result } = await lacuna.empire.inviteFriend({ email, custom_message: message }); + if (result && result.sent.includes(email)) { + vex.alert('Invite email sent!'); + } else { + vex.alert('Invite email failed to send.'); + } } } diff --git a/app/components/login.tsx b/app/components/login.tsx index deb5fe0e..778d653d 100644 --- a/app/components/login.tsx +++ b/app/components/login.tsx @@ -1,7 +1,7 @@ import React from 'react'; -import EmpireService from 'app/services/empire'; import WindowsStore from 'app/stores/windows'; import environment from 'app/environment'; +import lacuna from 'app/lacuna'; import YAHOO from 'app/shims/yahoo'; @@ -35,10 +35,15 @@ class LoginWindow extends React.Component { const fingerprint = 'todo'; // TODO: handle empire not founded error - const res = await EmpireService.login(empireName, password, fingerprint); - - if (res?.session_id) { - LoginDialog.fireEvent('onLoginSuccessful', { result: res }); + const { result } = await lacuna.empire.login({ + empire_name: empireName, + password, + api_key: 'anonymous', // TODO: add an API key + browser: fingerprint, + }); + + if (result?.session_id) { + LoginDialog.fireEvent('onLoginSuccessful', { result }); WindowsStore.closeAll(); if (rememberEmpire) { diff --git a/app/components/menu/topBar.tsx b/app/components/menu/topBar.tsx index ae9677ce..b0a50992 100644 --- a/app/components/menu/topBar.tsx +++ b/app/components/menu/topBar.tsx @@ -3,12 +3,14 @@ import classnames from 'classnames'; import { observer } from 'mobx-react'; import Icon from 'app/components/menu/icon'; -import EmpireService from 'app/services/empire'; import EmpireRPCStore from 'app/stores/rpc/empire'; import MenuStore, { PLANET_MAP_MODE } from 'app/stores/menu'; import WindowsStore from 'app/stores/windows'; import MailWindowStore from 'app/stores/window/mail'; import StatsWindowStore from 'app/stores/window/stats'; +import lacuna from 'app/lacuna'; +import LegacyHooks from 'app/legacyHooks'; +import ReactTooltip from 'react-tooltip'; class TopBar extends React.Component { render() { @@ -59,7 +61,19 @@ class TopBar extends React.Component { - EmpireService.logout()}> + { + await lacuna.empire.logout(); + + MenuStore.reset(); + + LegacyHooks.resetGame(); + + // Hide all our tooltips + ReactTooltip.hide(); + }} + > diff --git a/app/components/planetPanel.tsx b/app/components/planetPanel.tsx index 2d2cf811..bcea60b5 100644 --- a/app/components/planetPanel.tsx +++ b/app/components/planetPanel.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { types } from '@tlecommunity/client'; -import BodyService from 'app/services/body'; +import lacuna from 'app/lacuna'; import PlanetDetailsTab from 'app/components/planetPanel/planetDetailsTab'; import { Tabber } from 'app/components/tabber'; @@ -78,7 +78,7 @@ class PlanetPanel extends React.Component { async componentDidMount() { // TODO: send request with correct ID instead of `1` - const result = await BodyService.getStatus(1); + const { result } = await lacuna.body.getStatus({ body_id: 1 }); // lacuna.body.getStatus is typed as a full StatusBlock (types.Body.GetStatusResponse extends // StatusBlock), so the actual body fields are nested at result.body.body per the generated // types.Status.BodyBlock shape - double-check this against a real response, it may be that the diff --git a/app/components/register.tsx b/app/components/register.tsx index 2473d5fd..720e31a7 100644 --- a/app/components/register.tsx +++ b/app/components/register.tsx @@ -1,8 +1,9 @@ import React from 'react'; import WindowsStore from 'app/stores/windows'; -import EmpireService from 'app/services/empire'; import { Formik, Form, Field, ErrorMessage } from 'formik'; import { object, string, boolean, InferType } from 'yup'; +import lacuna from 'app/lacuna'; +import * as util from 'app/util'; import YAHOO from 'app/shims/yahoo'; @@ -37,14 +38,14 @@ class RegisterWindow extends React.Component { } async componentDidMount() { - const result = await EmpireService.fetchCaptcha(); + const { result } = await lacuna.empire.fetchCaptcha(); if (result) { this.setState({ captcha: { guid: result.guid, url: result.url } }); } } async submit(values: EmpireSchema) { - const empireId = await EmpireService.create({ + const { result } = await lacuna.empire.create({ name: values.empireName, email: values.email, password: values.password, @@ -53,6 +54,7 @@ class RegisterWindow extends React.Component { captcha_guid: this.state.captcha.guid, captcha_solution: values.captcha, }); + const empireId = util.int(result); if (empireId && empireId > 1) { WindowsStore.close('register'); diff --git a/app/game.tsx b/app/game.tsx index f56a8c8b..b36fea4f 100644 --- a/app/game.tsx +++ b/app/game.tsx @@ -11,7 +11,7 @@ import WindowsStore from 'app/stores/windows'; import environment from 'app/environment'; import resources from 'app/json/resources.json'; -import EmpireService from 'app/services/empire'; +import lacuna from 'app/lacuna'; import * as vex from 'app/vex'; @@ -126,7 +126,8 @@ if (typeof YAHOO.lacuna.Game === 'undefined' || !YAHOO.lacuna.Game) { SessionStore.update(session); - EmpireService.getStatus() + lacuna.empire + .getStatus() .then(() => { Game.Run(); }) @@ -185,6 +186,7 @@ if (typeof YAHOO.lacuna.Game === 'undefined' || !YAHOO.lacuna.Game) { const { result } = oArgs; // remember session Game.SetSession(result.session_id); + lacuna.session.set(result.session_id); Game.RemoveCookie('locationId'); Game.RemoveCookie('locationView'); diff --git a/app/lacuna.ts b/app/lacuna.ts index 9df49594..4c96cd9f 100644 --- a/app/lacuna.ts +++ b/app/lacuna.ts @@ -1,7 +1,68 @@ import { Lacuna } from '@tlecommunity/client'; +import * as vex from 'app/vex'; +import WindowsStore from 'app/stores/windows'; +import * as util from 'app/util'; +import YAHOO from 'app/shims/yahoo'; import environment from './environment'; +import { splitStatus } from './server'; const lacuna = new Lacuna({ serverUrl: environment.getServerUrl() }); lacuna.log.setLogLevel('info'); +// eslint-disable-next-line consistent-return +lacuna.onResponse(({ request, response, retry }) => { + if (response.result) { + if ( + (request.module === 'empire' || request.module === 'body') && + request.method === 'get_status' + ) { + splitStatus(response.result); + } else if (response.result.status) { + splitStatus(response.result.status); + } + } + + if (response.error) { + const { code, message } = response.error; + + // Needs to solve captcha + if (code === 1016) { + return new Promise((resolve, reject) => { + WindowsStore.add('captcha', { + onCaptchaComplete: () => retry().then(resolve, reject), + }); + }); + } + + if (code === 1100) { + // Empire not founded + const empireId = util.int(response.error.data?.empire_id); + const { Game } = YAHOO.lacuna; + + Game.SpeciesCreator = new YAHOO.lacuna.CreateSpecies({ + handleCancel: () => { + WindowsStore.add('login'); + }, + }); + + Game.SpeciesCreator.subscribe( + 'onCreateSuccessful', + (oArgs: any) => { + Game.LoginDialog.fireEvent('onLoginSuccessful', oArgs); + }, + this, + true + ); + + WindowsStore.closeAll(); + Game.SpeciesCreator.show(empireId); + + return new Promise(() => {}); + } + + vex.alert(`${message} ${code ? `(${code})` : ''}`); + console.error('Request error: ', response.error); + } +}); + export default lacuna; diff --git a/app/lacunaCall.ts b/app/lacunaCall.ts deleted file mode 100644 index 72c4806a..00000000 --- a/app/lacunaCall.ts +++ /dev/null @@ -1,82 +0,0 @@ -import * as vex from 'app/vex'; -import MenuStore from 'app/stores/menu'; -import { splitStatus, openCaptchaAndRetry, handleEmpireNotFounded } from 'app/server'; - -interface LacunaError { - code: number; - message: string; - data?: any; -} - -interface LacunaResponse { - result?: T; - error?: LacunaError; -} - -interface CallLacunaOptions { - // Set for endpoints where the whole response *is* a status block (e.g. get_status-shaped - // methods), matching app/server.ts's handleSuccess rule for `options.method === 'get_status'`. - isStatusCall?: boolean; -} - -export class LacunaCallError extends Error { - code: number; - - data?: any; - - constructor(error: LacunaError) { - super(error.message); - this.code = error.code; - this.data = error.data; - } -} - -function handleError( - fn: () => Promise>, - options: CallLacunaOptions, - error: LacunaError -): Promise { - if (error.code === 1016) { - return new Promise((resolve, reject) => { - openCaptchaAndRetry(() => { - // eslint-disable-next-line @typescript-eslint/no-use-before-define - callLacuna(fn, options).then(resolve, reject); - }); - }); - } - - if (error.code === 1100) { - handleEmpireNotFounded(error); - // Matches app/server.ts: the original request's promise is abandoned in favor of the - // species-creator flow, it never resolves or rejects. - return new Promise(() => {}); - } - - vex.alert(`${error.message} ${error.code ? `(${error.code})` : ''}`); - console.error('Request error: ', error); - throw new LacunaCallError(error); -} - -export async function callLacuna( - fn: () => Promise>, - options: CallLacunaOptions = {} -): Promise { - MenuStore.showLoader(); - const { result, error } = await fn(); - MenuStore.hideLoader(); - - if (error) { - return handleError(fn, options, error); - } - - if (result) { - const anyResult = result as any; - if (anyResult.status) { - splitStatus(anyResult.status); - } else if (options.isStatusCall) { - splitStatus(anyResult); - } - } - - return result; -} diff --git a/app/server.test.ts b/app/server.test.ts deleted file mode 100644 index ccba241a..00000000 --- a/app/server.test.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { addSession, createBody, createUrl } from 'app/server'; -import SessionStore from 'app/stores/session'; - -const SESSION_ID = 'test-session'; - -beforeEach(() => { - SessionStore.update(SESSION_ID); -}); - -test('it should add a session to the request', () => { - expect( - addSession({ module: 'empire', method: 'get_status', params: [], addSession: true }) - ).toMatchObject({ - module: 'empire', - method: 'get_status', - params: [SESSION_ID], - addSession: true, - }); - - expect( - addSession({ module: 'empire', method: 'get_status', params: {}, addSession: true }) - ).toMatchObject({ - module: 'empire', - method: 'get_status', - params: { session_id: SESSION_ID }, - addSession: true, - }); - - SessionStore.update(''); - - expect( - addSession({ module: 'empire', method: 'get_status', params: [], addSession: true }) - ).toMatchObject({ - module: 'empire', - method: 'get_status', - params: [], - addSession: true, - }); - - expect( - addSession({ module: 'empire', method: 'get_status', params: {}, addSession: true }) - ).toMatchObject({ - module: 'empire', - method: 'get_status', - params: {}, - addSession: true, - }); -}); - -test('it should not add a session to the request when addSession is false', () => { - expect( - addSession({ module: 'empire', method: 'get_status', params: [], addSession: false }) - ).toMatchObject({ - module: 'empire', - method: 'get_status', - params: [], - addSession: false, - }); - - expect( - addSession({ module: 'empire', method: 'get_status', params: {}, addSession: false }) - ).toMatchObject({ - module: 'empire', - method: 'get_status', - params: {}, - addSession: false, - }); - - SessionStore.update(''); - - expect( - addSession({ module: 'empire', method: 'get_status', params: [], addSession: false }) - ).toMatchObject({ - module: 'empire', - method: 'get_status', - params: [], - addSession: false, - }); - - expect( - addSession({ module: 'empire', method: 'get_status', params: {}, addSession: false }) - ).toMatchObject({ - module: 'empire', - method: 'get_status', - params: {}, - addSession: false, - }); -}); - -test('it should create a valid request body', () => { - expect( - createBody({ module: 'body', method: 'get_buildings', params: ['body-id'], addSession: true }) - ).toMatchObject({ - jsonrpc: '2.0', - id: 1, - method: 'get_buildings', - params: ['body-id'], - }); -}); - -test('it should create a valid url', () => { - expect( - createUrl({ module: 'body', method: 'get_buildings', params: ['body-id'], addSession: true }) - ).toBe('http://localhost:3001/body'); -}); - -// test('calling a known server function should return a known response', (done) => { -// server.call({ -// module: 'empire', -// method: 'login', -// addSession: false, -// params: ['empire-name', 'password'], -// success: (res: any) => { -// expect(res.session_id).toBe('this-is-a-session-id'); -// expect(res.status).toBeDefined(); -// done(); -// }, -// }); -// }); - -// test('calling an unknown server function should trigger the error handling', (done) => { -// server.call({ -// module: 'unknown-module', -// method: 'unknown-method', -// addSession: true, -// params: [], -// error: (error: any) => { -// expect(error.message).toBe('Invalid request.'); -// expect(error.data).toBeNull(); -// done(); -// }, -// }); -// }); diff --git a/app/server.ts b/app/server.ts index 2361ea10..0e710fdb 100644 --- a/app/server.ts +++ b/app/server.ts @@ -1,69 +1,9 @@ -import _ from 'lodash'; -import $ from 'jquery'; -import * as util from 'app/util'; -import * as vex from 'app/vex'; - import ServerRPCStore from 'app/stores/rpc/server'; import EmpireRPCStore from 'app/stores/rpc/empire'; import BodyRPCStore from 'app/stores/rpc/body'; -import MenuStore from 'app/stores/menu'; -import SessionStore from 'app/stores/session'; -import WindowsStore from 'app/stores/windows'; -import environment from 'app/environment'; import { types } from '@tlecommunity/client'; -import YAHOO from 'app/shims/yahoo'; - -interface ServerRequest { - module: string; - method: string; - params: object | Array; - addSession: boolean; - success?: (result: any) => void; - error?: (result: any) => void; -} - -interface ServerError { - code: number; - message: string; - data?: any; -} - -interface RequestBody { - jsonrpc: '2.0'; - id: number; - method: string; - params: object | Array; -} - -export const addSession = function (options: ServerRequest): ServerRequest { - const sessionId = SessionStore.session; - - if (options.addSession === true && sessionId) { - if (_.isArray(options.params)) { - options.params = [sessionId].concat(options.params); - } else { - options.params = { ...options.params, session_id: sessionId }; - } - } - - return options; -}; - -export const createBody = function (options: ServerRequest): RequestBody { - return { - jsonrpc: '2.0', - id: 1, - method: options.method, - params: options.params, - }; -}; - -export const createUrl = function (options: ServerRequest): string { - return environment.getServerUrl() + options.module; -}; - // // Split the status message into server, body, empire // and call the corresponding actions @@ -81,115 +21,4 @@ export const splitStatus = function (status: types.Status.StatusBlock): void { } }; -const handleSuccess = function (options: ServerRequest, result: any): void { - if (result) { - if (result.status) { - splitStatus(result.status); - } else if (options.method === 'get_status') { - splitStatus(result); - } - } - - if (typeof options.success === 'function') { - options.success(result); - } -}; - -const handleError = function (options: ServerRequest, error: ServerError): void { - vex.alert(`${error.message} ${error.code ? `(${error.code})` : ''}`); - console.error('Request error: ', error); - - if (typeof options.error === 'function') { - options.error(error); - } -}; - -export const openCaptchaAndRetry = function (retry: () => void): void { - // Needs to solve captcha - WindowsStore.add('captcha', { - onCaptchaComplete: () => retry(), - }); -}; - -export const handleEmpireNotFounded = function (this: unknown, error: ServerError): void { - // Empire not founded - const empireId = util.int(error.data.empire_id); - const Lacuna = YAHOO.lacuna; - const { Game } = Lacuna; - - Game.SpeciesCreator = new Lacuna.CreateSpecies({ - handleCancel: () => { - WindowsStore.add('login'); - }, - }); - - Game.SpeciesCreator.subscribe( - 'onCreateSuccessful', - (oArgs: any) => { - Game.LoginDialog.fireEvent('onLoginSuccessful', oArgs); - }, - this, - true - ); - - WindowsStore.closeAll(); - Game.SpeciesCreator.show(empireId); -}; - -const sendRequest = function ( - url: string, - data: string, - options: ServerRequest, - retry: () => void -): void { - console.log('Calling', `${options.module}/${options.method}`, options.params); - - $.ajax({ - data, - dataType: 'json', - type: 'POST', - contentType: 'application/json', - url, - - success(json, textStatus, jqXHR) { - MenuStore.hideLoader(); - - if (textStatus === 'success' && jqXHR.status === 200) { - handleSuccess(options, util.fixNumbers(json.result)); - } - }, - - error(jqXHR) { - MenuStore.hideLoader(); - const error: ServerError = jqXHR?.responseJSON?.error || { - code: -1, - message: jqXHR.responseText || 'Could not communicate with server', - }; - - if (error.code === 1016) { - openCaptchaAndRetry(retry); - } else if (error.code === 1100) { - handleEmpireNotFounded(error); - } else { - handleError(options, error); - } - }, - }); -}; - -export const call = function (obj: ServerRequest): void { - MenuStore.showLoader(); - - const options = addSession(obj); - const body = createBody(options); - const data = JSON.stringify(body); - const url = createUrl(options); - - const retry = function () { - call(obj); - }; - - sendRequest(url, data, options, retry); -}; - -export default { call, splitStatus }; +export default { splitStatus }; diff --git a/app/services/base.ts b/app/services/base.ts deleted file mode 100644 index 8705558d..00000000 --- a/app/services/base.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { types } from '@tlecommunity/client'; -import server from 'app/server'; -import { EmpireCreateResponse } from 'app/interfaces'; - -class ServiceBase { - // No generated lacuna.empire.create endpoint exists yet - this is the last method still - // going through the legacy server.call path. - call( - module: 'empire', - method: 'create', - params: types.Empire.CreateParams, - addSession?: boolean - ): Promise; - - call(module: string, method: string, params: any, addSession = true): Promise { - return new Promise((resolve, reject) => { - server.call({ - module, - method, - params, - addSession, - success: (res: any) => { - resolve(res); - }, - error: (error: any) => { - reject(error); - }, - }); - }); - } -} - -export default ServiceBase; diff --git a/app/services/body.ts b/app/services/body.ts deleted file mode 100644 index 2f198862..00000000 --- a/app/services/body.ts +++ /dev/null @@ -1,10 +0,0 @@ -import lacuna from 'app/lacuna'; -import { callLacuna } from 'app/lacunaCall'; - -class BodyService { - getStatus(id: number) { - return callLacuna(() => lacuna.body.getStatus({ body_id: id }), { isStatusCall: true }); - } -} - -export default new BodyService(); diff --git a/app/services/empire.ts b/app/services/empire.ts deleted file mode 100644 index 1f033922..00000000 --- a/app/services/empire.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { types } from '@tlecommunity/client'; -import lacuna from 'app/lacuna'; -import { callLacuna } from 'app/lacunaCall'; -import * as vex from 'app/vex'; -import BoostsRPCStore from 'app/stores/rpc/empire/boosts'; -import environment from 'app/environment'; -import InviteRPCStore from 'app/stores/rpc/empire/invite'; -import ReactTooltip from 'react-tooltip'; -import server from 'app/server'; -import ServiceBase from 'app/services/base'; -import MenuStore from 'app/stores/menu'; - -import LegacyHooks from 'app/legacyHooks'; - -class EmpireService extends ServiceBase { - async getStatus() { - return callLacuna(() => lacuna.empire.getStatus(), { isStatusCall: true }); - } - - async create(empire: types.Empire.CreateParams) { - // No generated lacuna.empire.create endpoint exists yet (types.Empire.CreateParams/ - // CreateResponse are generated, but the client's Empire class has no method for it) - - // stays on the legacy path. - return this.call('empire', 'create', empire); - } - - async fetchCaptcha() { - return callLacuna(() => lacuna.empire.fetchCaptcha()); - } - - async login(name: string, password: string, browserFingerprint: string) { - return callLacuna(() => - lacuna.empire.login({ - name, - password, - api_key: environment.getApiKey(), - browser: browserFingerprint, - }) - ); - } - - async logout() { - await callLacuna(() => lacuna.empire.logout()); - - MenuStore.reset(); - - LegacyHooks.resetGame(); - - // Hide all our tooltips - ReactTooltip.hide(); - } - - async getBoosts() { - const result = await callLacuna(() => lacuna.empire.viewBoosts()); - if (result) { - BoostsRPCStore.update(result); - } - } - - async setBoost(type: string, weeks: number) { - const result = await callLacuna(() => lacuna.empire.setBoost({ type, weeks })); - if (result) { - BoostsRPCStore.update(result); - } - } - - // No generated lacuna endpoint exists for get_invite_friend_url - stays on the legacy path. - getInviteFriendUrl() { - server.call({ - module: 'empire', - method: 'get_invite_friend_url', - params: [], - addSession: true, - success: (result: any) => { - InviteRPCStore.update(result); - }, - }); - } - - // No generated lacuna endpoint exists for invite_friend - stays on the legacy path. - inviteFriend(email: string, message: string) { - server.call({ - module: 'empire', - method: 'invite_friend', - params: [email, message], - addSession: true, - success: () => { - vex.alert('Invite email sent!'); - }, - }); - } -} - -export default new EmpireService(); diff --git a/app/util.test.ts b/app/util.test.ts index 80d2c773..89bdca77 100644 --- a/app/util.test.ts +++ b/app/util.test.ts @@ -31,6 +31,7 @@ test('util.int', () => { expect(util.int('1.0')).toBe(1); expect(util.int('1.0sdfsl')).toBe(1); expect(util.int(1.111111)).toBe(1); + expect(util.int(undefined)).toBe(0); }); test('util.formatTime', () => { diff --git a/app/util.ts b/app/util.ts index ff639d67..ee7d2dc3 100644 --- a/app/util.ts +++ b/app/util.ts @@ -54,7 +54,8 @@ export const reduceNumber = function (number: number) { return Math.floor(number).toString() || '0'; }; -export const int = function (value: string | number) { +export const int = function (value: string | number | undefined) { + if (value === undefined) return 0; return typeof value === 'string' ? parseInt(value, 10) : Math.trunc(value + 0); }; diff --git a/package-lock.json b/package-lock.json index 139ed21d..c5b43e1d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "app", "version": "0.0.1", "dependencies": { - "@tlecommunity/client": "^1.0.0", + "@tlecommunity/client": "^1.2.0", "bulma": "^0.9.4", "classnames": "^2.3.1", "create-react-class": "^15.6.3", @@ -1230,9 +1230,9 @@ } }, "node_modules/@tlecommunity/client": { - "version": "1.0.0", - "resolved": "https://gitea.allosaurus-chromatic.ts.net/api/packages/tlecommunity/npm/%40tlecommunity%2Fclient/-/1.0.0/client-1.0.0.tgz", - "integrity": "sha512-Rl5Bmjxgu1MpjMIeNKtu89Wv2EpEKUzAB3pWy2+QbUGYkd5bDjIcK73pgGT4esN5xnn+PgVAdTyrqXhtaLjMuA==", + "version": "1.2.0", + "resolved": "https://gitea.allosaurus-chromatic.ts.net/api/packages/tlecommunity/npm/%40tlecommunity%2Fclient/-/1.2.0/client-1.2.0.tgz", + "integrity": "sha512-gKHji/w0NXdEeAJPuFWoudyQ0SE7Whp1oHvymPie9O4fIPDef+dIK/mm8THzws0Cu/Snr05sIWK9DyJFFt+mAw==", "license": "MIT", "dependencies": { "@types/lodash": "^4.17.25", @@ -8364,9 +8364,9 @@ } }, "@tlecommunity/client": { - "version": "1.0.0", - "resolved": "https://gitea.allosaurus-chromatic.ts.net/api/packages/tlecommunity/npm/%40tlecommunity%2Fclient/-/1.0.0/client-1.0.0.tgz", - "integrity": "sha512-Rl5Bmjxgu1MpjMIeNKtu89Wv2EpEKUzAB3pWy2+QbUGYkd5bDjIcK73pgGT4esN5xnn+PgVAdTyrqXhtaLjMuA==", + "version": "1.2.0", + "resolved": "https://gitea.allosaurus-chromatic.ts.net/api/packages/tlecommunity/npm/%40tlecommunity%2Fclient/-/1.2.0/client-1.2.0.tgz", + "integrity": "sha512-gKHji/w0NXdEeAJPuFWoudyQ0SE7Whp1oHvymPie9O4fIPDef+dIK/mm8THzws0Cu/Snr05sIWK9DyJFFt+mAw==", "requires": { "@types/lodash": "^4.17.25", "lodash": "^4.18.1", diff --git a/package.json b/package.json index a2843ff3..bff9f5a3 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ }, "homepage": "https://github.com/tlecommunity/app", "dependencies": { - "@tlecommunity/client": "^1.0.0", + "@tlecommunity/client": "^1.2.0", "bulma": "^0.9.4", "classnames": "^2.3.1", "create-react-class": "^15.6.3",