Skip to content

Commit ebc2c51

Browse files
committed
add quiz CRUD interface
1 parent 8306060 commit ebc2c51

File tree

25 files changed

+510
-11
lines changed

25 files changed

+510
-11
lines changed

app/models/quiz.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import DS from "ember-data";
2+
3+
export default DS.Model.extend({
4+
title: DS.attr(),
5+
description: DS.attr(),
6+
image: DS.attr(),
7+
duration: DS.attr(),
8+
maxAttempts: DS.attr(),
9+
startDate: DS.attr(),
10+
endDate: DS.attr(),
11+
addedBy: DS.attr(),
12+
questions: DS.hasMany('question')
13+
})

app/pods/components/nav-bar/template.hbs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
</li>
1818
{{/link-to}}
1919

20+
{{#link-to 'quiz'}}
21+
<li class="nav-items pointer">
22+
Quiz
23+
</li>
24+
{{/link-to}}
25+
2026
{{!--
2127
<a href="https://online.codingblocks.com/">
2228
<li class="nav-items pointer">
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import Component from '@ember/component';
2+
import { inject as service } from '@ember/service';
3+
import { task, timeout } from 'ember-concurrency';
4+
import { computed } from '@ember/object';
5+
6+
export default Component.extend({
7+
notify: service(),
8+
store: service(),
9+
questionFilterTask: task(function * (str) {
10+
yield timeout(250)
11+
const questions = yield this.get('store').query('question', {
12+
filter: {
13+
title: {
14+
$iLike: `%${str}%`
15+
}
16+
}
17+
})
18+
return questions.toArray()
19+
}),
20+
startDateMoment: computed('quiz.startDate', {
21+
get (key) {
22+
return moment(this.get('quiz.startDate'))
23+
},
24+
set (key, val) {
25+
this.set('quiz.startDate', val.format('YYYY-MM-DD HH:mm:ss'))
26+
}
27+
}),
28+
endDateMoment: computed('quiz.endDate', {
29+
get (key) {
30+
return moment(this.get('quiz.endDate'))
31+
},
32+
set (key, val) {
33+
this.set('quiz.endDate', val.format('YYYY-MM-DD HH:mm:ss'))
34+
}
35+
}),
36+
actions: {
37+
save () {
38+
const onSave = this.get('onSave')
39+
if (typeof onSave === 'function') {
40+
Promise.resolve(onSave()).then(() => {
41+
this.get('notify').success('Save Successful')
42+
})
43+
} else {
44+
throw new Error('[Component] quiz-editor: onSave attr must be a closure!')
45+
}
46+
}
47+
}
48+
});
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<div class="container">
2+
<div class="row">
3+
<div class="col-2">
4+
<label>Title</label>
5+
</div>
6+
<div class="col-6">
7+
{{input type="text" value=quiz.title}}
8+
</div>
9+
</div>
10+
<div class="row">
11+
<div class="col-2">
12+
<label>Description</label>
13+
</div>
14+
<div class="col-6">
15+
{{textarea type="text" value=quiz.description}}
16+
</div>
17+
</div>
18+
{{#unless quiz.isNew}}
19+
<div class="row">
20+
<div class="col-2">
21+
<label>Questions</label>
22+
</div>
23+
<div class="col-6">
24+
{{#power-select-multiple
25+
search=(perform questionFilterTask)
26+
selected=quiz.questions
27+
onchange=(action (mut quiz.questions ))
28+
as |question|}}
29+
{{question.title}}
30+
{{/power-select-multiple}}
31+
</div>
32+
</div>
33+
{{/unless}}
34+
35+
<div class="row">
36+
<div class="col-2">
37+
<label>Image Url:</label>
38+
</div>
39+
<div class="col-6">
40+
{{input type="text" value=quiz.image}}
41+
</div>
42+
</div>
43+
44+
<div class="row">
45+
<div class="col-2">
46+
<label>Duration </label>
47+
</div>
48+
<div class="col-6">
49+
{{input type="text" value=quiz.duration}}
50+
</div>
51+
</div>
52+
<div class="row">
53+
<div class="col-2">
54+
<label>Max Attempts</label>
55+
</div>
56+
<div class="col-6">
57+
{{input type="text" value=quiz.maxAttempts}}
58+
</div>
59+
</div>
60+
<div class="row">
61+
<div class="col-2">
62+
<label>Start Date</label>
63+
</div>
64+
<div class="col-6">
65+
{{ember-datetime-picker value=startDateMoment }}
66+
{{!-- {{input type="text" value=quiz.startDate}} --}}
67+
</div>
68+
</div>
69+
<div class="row">
70+
<div class="col-2">
71+
<label>End Date</label>
72+
</div>
73+
<div class="col-6">
74+
{{ember-datetime-picker value=endDateMoment }}
75+
76+
{{!-- {{input type="text" value=quiz.endDate}} --}}
77+
</div>
78+
</div>
79+
80+
<div class="button-solid">
81+
<button {{action 'save'}}>Save Changes</button>
82+
</div>
83+
</div>
84+

app/pods/quiz/id/controller.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Controller from '@ember/controller';
2+
3+
export default Controller.extend({
4+
actions: {
5+
saveQuiz () {
6+
return this.get('model').save()
7+
}
8+
}
9+
});

app/pods/quiz/id/route.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import Route from '@ember/routing/route';
2+
3+
export default Route.extend({
4+
model (params) {
5+
return this.store.findRecord('quiz', params.id, {
6+
include: 'questions,user'
7+
})
8+
}
9+
});

app/pods/quiz/id/template.hbs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{{quiz-editor quiz=model onSave=(action 'saveQuiz')}}

app/pods/quiz/index/controller.js

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import Controller from '@ember/controller';
2+
import { task, timeout } from 'ember-concurrency'
3+
4+
export default Controller.extend({
5+
searchString: '',
6+
searchTask: task(function * () {
7+
yield timeout(250)
8+
9+
let searchStr = this.get('searchString').trim()
10+
11+
const quizzes = yield this.get('store').query('quiz', {
12+
filter: {
13+
title: {
14+
$iLike: `%${this.get('searchString')}%`
15+
}
16+
}
17+
})
18+
19+
this.set('quizzes', quizzes)
20+
}).restartable(),
21+
actions: {
22+
deleteQuiz (quiz) {
23+
return quiz.destroyRecord()
24+
}
25+
}
26+
});

app/pods/quiz/index/route.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import Route from '@ember/routing/route';
2+
3+
export default Route.extend({
4+
model () {
5+
return this.store.query('quiz', {
6+
include: 'user'
7+
})
8+
},
9+
setupController (controller, model) {
10+
controller.set("quizzes", model)
11+
}
12+
});

app/pods/quiz/index/template.hbs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<div class="container">
2+
<div>
3+
<div class="button-solid">
4+
{{#link-to 'quiz.new' class="white"}}
5+
<button>+ Add Quiz</button>
6+
{{/link-to}}
7+
</div>
8+
<br>
9+
<div class="row justify-content-center">
10+
<p class="card-title">Filter By Quiz Title: </p> {{input type="text" class="form-control" placeholder="Enter Question Name" key-up=(perform searchTask) value=searchString}}
11+
</div>
12+
</div>
13+
{{#each quizzes as |quiz|}}
14+
<div class="row">
15+
<div class="card">
16+
<div class="card-body">
17+
<h5 class="card-title">Quiz#{{quiz.id}}: {{quiz.title}}</h5>
18+
<p class="card-text">
19+
{{quiz.description}}
20+
</p>
21+
<div class="button-solid">
22+
{{#confirm-dialog
23+
dialogClass="custom-confirm-dialog"
24+
title="Delete Question"
25+
text="Are you sure you want to delete this question?"}}
26+
<button {{action "deleteQuiz" quiz}}>Delete</button>
27+
{{/confirm-dialog}}
28+
</div>
29+
<div class="button-solid">
30+
{{#link-to 'quiz.id' quiz.id class="white"}}
31+
<button>Edit</button>
32+
{{/link-to}}
33+
</div>
34+
</div>
35+
</div>
36+
</div>
37+
{{/each}}
38+
</div>
39+
{{outlet}}

0 commit comments

Comments
 (0)