Many changes haha
This commit is contained in:
parent
0c5a350425
commit
ae43285239
16 changed files with 182 additions and 17 deletions
5
app/adapters/application.js
Normal file
5
app/adapters/application.js
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
import JSONAPIAdapter from '@ember-data/adapter/json-api';
|
||||||
|
|
||||||
|
export default class ApplicationAdapter extends JSONAPIAdapter {
|
||||||
|
host = 'https://www.themealdb.com/api/json/v1/1';
|
||||||
|
}
|
40
app/adapters/meal.js
Normal file
40
app/adapters/meal.js
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import ApplicationAdapter from './application';
|
||||||
|
import { dasherize } from '@ember/string';
|
||||||
|
|
||||||
|
export default class MealAdapter extends ApplicationAdapter {
|
||||||
|
async findRecord(store, model, id) {
|
||||||
|
let result = await fetch(`${this.host}/lookup.php?i=${id}`);
|
||||||
|
let json = await result.json();
|
||||||
|
return normalize(json.meals[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async queryRecord(store, model, query) {
|
||||||
|
if (query === 'random') {
|
||||||
|
let result = await fetch(`${this.host}/random.php`);
|
||||||
|
let json = await result.json();
|
||||||
|
return normalize(json.meals[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function normalize(obj) {
|
||||||
|
let attributes = {};
|
||||||
|
|
||||||
|
Object.keys(obj).forEach(key => attributes[cleanKey(key)] = obj[key]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
type: 'meal',
|
||||||
|
id: attributes.id,
|
||||||
|
attributes,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanKey(key) {
|
||||||
|
key = dasherize(key);
|
||||||
|
key = key.replace('str-', '');
|
||||||
|
if (key === 'id-meal') key = 'id';
|
||||||
|
if (key === 'meal') key = 'name';
|
||||||
|
return key;
|
||||||
|
}
|
3
app/components/meal-tag.hbs
Normal file
3
app/components/meal-tag.hbs
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<span class="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2">
|
||||||
|
#{{yield}}
|
||||||
|
</span>
|
|
@ -7,7 +7,7 @@
|
||||||
@model={{meal}}
|
@model={{meal}}
|
||||||
as |item|>
|
as |item|>
|
||||||
<item.handle>
|
<item.handle>
|
||||||
<RecipePreview @meal={{meal}} />
|
<RecipePreview @meal={{meal}} {{on "click" this.openMealDetails}} />
|
||||||
</item.handle>
|
</item.handle>
|
||||||
</group.item>
|
</group.item>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
@ -15,6 +15,6 @@
|
||||||
|
|
||||||
<button
|
<button
|
||||||
{{on "click" this.addRecipe}}
|
{{on "click" this.addRecipe}}
|
||||||
class="bg-blue-500 hover:bg-blue-400 text-white font-bold py-2 px-4 border-b-4 border-blue-700 hover:border-blue-500 rounded">
|
class="w-full bg-teal-500 hover:bg-teal-400 text-white font-bold mt-4 py-2 px-4 border-b-4 border-teal-700 hover:border-teal-500 rounded">
|
||||||
Button
|
Add Another Recipe
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -3,14 +3,24 @@ import { tracked } from "@glimmer/tracking";
|
||||||
import { action } from "@ember/object";
|
import { action } from "@ember/object";
|
||||||
import { A } from '@ember/array';
|
import { A } from '@ember/array';
|
||||||
import { task } from 'ember-concurrency';
|
import { task } from 'ember-concurrency';
|
||||||
|
import { inject as service } from '@ember/service';
|
||||||
|
|
||||||
export default class RecipeListComponent extends Component {
|
export default class RecipeListComponent extends Component {
|
||||||
|
@service store;
|
||||||
@tracked items = A([]);
|
@tracked items = A([]);
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super(...arguments);
|
||||||
|
this.assignExistingItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
async assignExistingItems() {
|
||||||
|
let items = await this.store.peekAll('meal');
|
||||||
|
this.items = items;
|
||||||
|
}
|
||||||
|
|
||||||
@(task(function * () {
|
@(task(function * () {
|
||||||
let response = yield fetch('https://www.themealdb.com/api/json/v1/1/random.php');
|
return yield this.store.queryRecord('meal', 'random');
|
||||||
response = yield response.json();
|
|
||||||
return response.meals[0];
|
|
||||||
})) fetchRecipe;
|
})) fetchRecipe;
|
||||||
|
|
||||||
@action
|
@action
|
||||||
|
@ -20,7 +30,6 @@ export default class RecipeListComponent extends Component {
|
||||||
|
|
||||||
@action
|
@action
|
||||||
async addRecipe() {
|
async addRecipe() {
|
||||||
let recipe = await this.fetchRecipe.perform();
|
await this.fetchRecipe.perform();
|
||||||
this.items.pushObject(recipe);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,19 +1,19 @@
|
||||||
<div class="max-w-sm w-full lg:max-w-full lg:flex">
|
<div class="max-w-sm w-full lg:max-w-full lg:flex">
|
||||||
<div class="h-48 lg:h-auto lg:w-48 flex-none bg-cover text-center overflow-hidden"
|
<div class="h-48 lg:h-auto lg:w-48 flex-none bg-cover text-center overflow-hidden"
|
||||||
style="background-image: url('{{@meal.strMealThumb}}')">
|
style="background-image: url('{{@meal.mealThumb}}')">
|
||||||
</div>
|
</div>
|
||||||
<div class="border-r border-b border-l border-gray-400 lg:border-l-0 lg:border-t lg:border-gray-400 bg-white p-4 flex flex-col justify-between leading-normal">
|
<div class="border-r border-b border-l border-gray-400 lg:border-l-0 lg:border-t lg:border-gray-400 bg-white p-4 flex flex-col justify-between leading-normal">
|
||||||
<div class="mb-8">
|
<div class="mb-8">
|
||||||
<div class="text-gray-900 font-bold text-xl mb-2">
|
<div class="text-gray-900 font-bold text-xl mb-2">
|
||||||
{{@meal.strMeal}}
|
{{@meal.name}}
|
||||||
</div>
|
</div>
|
||||||
<p class="text-gray-700 text-base">
|
<p class="text-gray-700 text-base">
|
||||||
Lorem...
|
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatibus quia, nulla! Maiores et perferendis eaque, exercitationem praesentium nihil.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<span class="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2">#{{@meal.strCategory}}</span>
|
<MealTag>{{@meal.category}}</MealTag>
|
||||||
<span class="inline-block bg-gray-200 rounded-full px-3 py-1 text-sm font-semibold text-gray-700 mr-2">#{{@meal.strArea}}</span>
|
<MealTag>{{@meal.area}}</MealTag>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
14
app/models/meal.js
Normal file
14
app/models/meal.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
import DS from 'ember-data';
|
||||||
|
const { Model, attr } = DS;
|
||||||
|
|
||||||
|
export default class MealModel extends Model {
|
||||||
|
@attr name;
|
||||||
|
@attr dateModified;
|
||||||
|
@attr category;
|
||||||
|
@attr area;
|
||||||
|
@attr mealThumb;
|
||||||
|
@attr instructions;
|
||||||
|
@attr tags;
|
||||||
|
@attr youtube;
|
||||||
|
@attr source;
|
||||||
|
}
|
|
@ -7,4 +7,5 @@ export default class Router extends EmberRouter {
|
||||||
}
|
}
|
||||||
|
|
||||||
Router.map(function() {
|
Router.map(function() {
|
||||||
|
this.route('meal', { path: '/:id' });
|
||||||
});
|
});
|
||||||
|
|
7
app/routes/meal.js
Normal file
7
app/routes/meal.js
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
import Route from '@ember/routing/route';
|
||||||
|
|
||||||
|
export default class MealRoute extends Route {
|
||||||
|
model({ id }) {
|
||||||
|
return this.store.findRecord('meal', id);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,11 +1,10 @@
|
||||||
<HeaderNav />
|
<HeaderNav />
|
||||||
|
|
||||||
<div class="flex mb-4">
|
<div class="flex p-4">
|
||||||
<div class="w-1/4">
|
<div class="w-2/6">
|
||||||
<RecipeList />
|
<RecipeList />
|
||||||
</div>
|
</div>
|
||||||
<div class="w-3/4">
|
<div class="w-4/6 pl-4">
|
||||||
Content goes here.
|
|
||||||
{{outlet}}
|
{{outlet}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
13
app/templates/meal.hbs
Normal file
13
app/templates/meal.hbs
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<h1 class="text-5xl text-teal-500 font-hairline">
|
||||||
|
{{@model.name}}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
<p class="text-gray-700 text-base whitespace-pre-line">
|
||||||
|
{{@model.instructions}}
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<div class="mt-4">
|
||||||
|
<MealTag>{{@model.category}}</MealTag>
|
||||||
|
<MealTag>{{@model.area}}</MealTag>
|
||||||
|
</div>
|
26
tests/integration/components/meal-tag-test.js
Normal file
26
tests/integration/components/meal-tag-test.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupRenderingTest } from 'ember-qunit';
|
||||||
|
import { render } from '@ember/test-helpers';
|
||||||
|
import { hbs } from 'ember-cli-htmlbars';
|
||||||
|
|
||||||
|
module('Integration | Component | meal-tag', function(hooks) {
|
||||||
|
setupRenderingTest(hooks);
|
||||||
|
|
||||||
|
test('it renders', async function(assert) {
|
||||||
|
// Set any properties with this.set('myProperty', 'value');
|
||||||
|
// Handle any actions with this.set('myAction', function(val) { ... });
|
||||||
|
|
||||||
|
await render(hbs`<MealTag />`);
|
||||||
|
|
||||||
|
assert.equal(this.element.textContent.trim(), '');
|
||||||
|
|
||||||
|
// Template block usage:
|
||||||
|
await render(hbs`
|
||||||
|
<MealTag>
|
||||||
|
template block text
|
||||||
|
</MealTag>
|
||||||
|
`);
|
||||||
|
|
||||||
|
assert.equal(this.element.textContent.trim(), 'template block text');
|
||||||
|
});
|
||||||
|
});
|
12
tests/unit/adapters/application-test.js
Normal file
12
tests/unit/adapters/application-test.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Adapter | application', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let adapter = this.owner.lookup('adapter:application');
|
||||||
|
assert.ok(adapter);
|
||||||
|
});
|
||||||
|
});
|
12
tests/unit/adapters/meal-test.js
Normal file
12
tests/unit/adapters/meal-test.js
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Adapter | meal', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let adapter = this.owner.lookup('adapter:meal');
|
||||||
|
assert.ok(adapter);
|
||||||
|
});
|
||||||
|
});
|
13
tests/unit/models/meal-test.js
Normal file
13
tests/unit/models/meal-test.js
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Model | meal', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
// Replace this with your real tests.
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let store = this.owner.lookup('service:store');
|
||||||
|
let model = store.createRecord('meal', {});
|
||||||
|
assert.ok(model);
|
||||||
|
});
|
||||||
|
});
|
11
tests/unit/routes/meal-test.js
Normal file
11
tests/unit/routes/meal-test.js
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import { module, test } from 'qunit';
|
||||||
|
import { setupTest } from 'ember-qunit';
|
||||||
|
|
||||||
|
module('Unit | Route | meal', function(hooks) {
|
||||||
|
setupTest(hooks);
|
||||||
|
|
||||||
|
test('it exists', function(assert) {
|
||||||
|
let route = this.owner.lookup('route:meal');
|
||||||
|
assert.ok(route);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Add table
Reference in a new issue