Skip to content

Commit

Permalink
feat(client): allow to calculate future position
Browse files Browse the repository at this point in the history
  • Loading branch information
clemlatz committed May 5, 2024
1 parent 06e2b33 commit f17c320
Show file tree
Hide file tree
Showing 5 changed files with 155 additions and 23 deletions.
38 changes: 38 additions & 0 deletions client/app/controllers/locations/get.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Controller from '@ember/controller';
import { tracked } from '@glimmer/tracking';
import { action } from '@ember/object';

import type Location from 'sokown-client/models/location';
import type { Position } from 'sokown-client/types';

export default class LocationGetController extends Controller {
declare model: Location;
@tracked targetDate: string = _getCurrentDateAsString();
@tracked futurePosition: Position | null = null;

@action
setTargetDate(event: Event): void {
this.targetDate = (event.target as HTMLInputElement).value;
}

@action
async calculateFuturePosition(event: Event): Promise<void> {
event.preventDefault();

const targetLocationCode = this.model.id;
const targetTimestamp = new Date(this.targetDate).getTime();

const response = await fetch(
`/api/locations/${targetLocationCode}/position?targetDate=${targetTimestamp}`,
);
const json = await response.json();
const { x, y } = json.data.attributes;
this.futurePosition = { x, y };
}
}

function _getCurrentDateAsString() {
const now = new Date();
now.setMinutes(now.getMinutes() - now.getTimezoneOffset());
return now.toISOString().slice(0, 16);
}
32 changes: 32 additions & 0 deletions client/app/templates/locations/get.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,35 @@
<Position @position={{@model.position}} />
</dd>
</dl>

<h3>Calculate future position</h3>

<form class="row row-cols-lg-auto g-3 align-items-center" {{on "submit" this.calculateFuturePosition}}>
<div class="col-12">
<label class="visually-hidden" for="targetDate">Target date</label>
<div class="input-group">
<div class="input-group-text">Date</div>
<input
type="datetime-local"
class="form-control"
id="targetDate"
value={{this.targetDate}}
oninput={{this.setTargetDate}}
required
/>
</div>
</div>

<div class="col-12">
<button type="submit" class="btn btn-primary">Calculate</button>
</div>
</form>

{{#if this.futurePosition}}
<dl>
<dt id="future-position">Future position</dt>
<dd aria-labelledby="future-position">
<Position @position={{this.futurePosition}} />
</dd>
</dl>
{{/if}}
32 changes: 10 additions & 22 deletions client/mirage/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,27 +67,15 @@ function routes() {

this.get('/api/locations');

// These comments are here to help you get started. Feel free to delete them.
this.get('/api/locations/:id');

/*
Config (with defaults).
Note: these only affect routes defined *after* them!
*/

// this.urlPrefix = ''; // make this `http://localhost:8080`, for example, if your API is on a different server
// this.namespace = ''; // make this `/api`, for example, if your API is namespaced
// this.timing = 400; // delay for each request, automatically set to 0 during testing

/*
Shorthand cheatsheet:
this.get('/posts');
this.post('/posts');
this.get('/posts/:id');
this.put('/posts/:id'); // or this.patch
this.del('/posts/:id');
https://miragejs.com/docs/getting-started/overview/
*/
this.get('/api/locations/:id/position', () => {
return {
data: {
id: 'moon',
type: 'position',
attributes: { x: 1, y: 2 },
},
};
});
}
24 changes: 23 additions & 1 deletion client/tests/acceptance/locations-test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { module, test } from 'qunit';
import { visit } from '@1024pix/ember-testing-library';
import { setupMirage } from 'ember-cli-mirage/test-support';
import { click } from '@ember/test-helpers';
import { click, fillIn } from '@ember/test-helpers';
import 'qunit-dom';

import { setupApplicationTest } from 'sokown-client/tests/helpers';
Expand Down Expand Up @@ -47,6 +47,28 @@ module('Acceptance | locations', function (hooks) {
assert
.dom(screen.getByRole('definition', { name: 'Current position' }))
.hasText('1.000 2.000');
assert
.dom(screen.queryByRole('definition', { name: 'Future position' }))
.doesNotExist();
});

module('calculating future position', function () {
test('it queries and displays future position for target date', async function (assert) {
// when
const screen = await visit('/locations/moon');
await fillIn(
screen.getByLabelText('Target date'),
'2019-04-28T02:42:00',
);
await click(screen.getByRole('button', { name: 'Calculate' }));

// then
assert
.dom(
await screen.findByRole('definition', { name: 'Future position' }),
)
.hasText('1.000 2.000');
});
});
});
});
52 changes: 52 additions & 0 deletions client/tests/unit/controllers/location/get-test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { module, test } from 'qunit';
import sinon from 'sinon';

import { setupTest } from 'sokown-client/tests/helpers';
import type LocationGetController from 'sokown-client/controllers/locations/get';

module('Unit | Controller | location/get', function (hooks) {
setupTest(hooks);

module('setTargetDate', function () {
test('it sets target date', function (assert) {
// given
const controller = this.owner.lookup(
'controller:locations/get',
) as LocationGetController;
controller.set('targetDate', '2013-05-22T13:30:00');
const event = {
target: { value: '2019-04-28T02:42:00' },
} as unknown as Event;

// when
controller.setTargetDate(event);

// then
assert.strictEqual(controller.get('targetDate'), '2019-04-28T02:42:00');
});
});

module('calculateFuturePosition', function () {
test('it queries api for future position', async function (assert) {
// given
const controller = this.owner.lookup(
'controller:locations/get',
) as LocationGetController;
controller.set('model', { id: 'moon' });
controller.set('targetDate', '2013-05-22T21:30:00');
const event = new Event('submit');

const fetchStub = sinon.stub(window, 'fetch');
const body = JSON.stringify({ data: { attributes: { x: 1, y: 2 } } });
const response = new Response(body);
fetchStub.resolves(response);

// when
await controller.calculateFuturePosition(event);

// then
assert.ok(fetchStub.calledOnce);
assert.deepEqual(controller.get('futurePosition'), { x: 1, y: 2 });
});
});
});

0 comments on commit f17c320

Please sign in to comment.