Huge update: Front-end for client fixed.

This commit is contained in:
2017-12-20 16:39:11 +07:00
parent 8418a77e8c
commit 573f678c69
156 changed files with 33035 additions and 0 deletions

742
assets/js/components/client/question.js vendored Normal file
View File

@@ -0,0 +1,742 @@
import m from "mithril"
import stream from "mithril/stream"
import _ from "lodash"
import powerform from "powerform"
import { required } from "validatex"
import { Card, TextField, RadioGroup, Button, Checkbox } from "polythene-mithril"
import Section from "../../models/Section"
import SectionQuestion from "../../models/SectionQuestion"
import Question from "../../models/Question"
import QuestionAnswer from "../../models/QuestionAnswer"
import Answer from "../../models/Answer"
import Respondent from "../../models/Respondent"
const text = {
form: powerform({
req: function(v) {
if (!v) {
return "Tuliskan jawaban Anda"
}
},
}),
oninit: function() {
var lS = {}
if (!_.isNil(window.localStorage.answers)) {
lS = _.find(JSON.parse(window.localStorage.answers), function(o) {
return o.id == SectionQuestion.current.data.id
})
}
text.form.req(_.isNil(lS) ? "" : lS.answers[0].text)
},
view: function(vnode) {
var attrs = vnode.attrs
var data = attrs.data || {}
return m(TextField, {
id: data.elId || "question" + SectionQuestion.current.data.id,
label: data.text || SectionQuestion.current.data.attributes.text,
floatingLabel: true,
help: SectionQuestion.current.data.attributes.description,
onChange: function(state) {
text.form.req(state.value)
},
validate: function() {
return {
valid: text.form.req.isValid(),
error: text.form.req.error()
}
},
value: text.form.req()
})
}
}
const choice = {
form: powerform({
req: function(v) {
if (!v) {
return "Pilih salah satu jawaban di bawah ini"
}
var fill = _.find(SectionQuestion.current.data.attributes.choices, function(o) {
return o.id == v
})
if (fill.fillable && !text.form.isValid()) {
return "Tuliskan jawaban Anda"
}
}
}),
oninit: function() {
var lS = {}
if (!_.isNil(window.localStorage.answers)) {
lS = _.find(JSON.parse(window.localStorage.answers), function(o) {
return o.id == SectionQuestion.current.data.id
})
}
choice.form.req(_.isNil(lS) ? "" : lS.answers[0].choice)
},
oncreate: function(vnode) {
SectionQuestion.current.data.attributes.choices.map(function(c) {
if (c.fillable) {
var child = document.createElement("span")
// child.style.marginTop = "1.4em"
var input = { view: function() {
return m(text, {
data: {
elId: "fillable-" + c.id,
text: "Tuliskan"
}
})
}}
/* Get parent */
var parent = document.getElementById("choice-" + c.id).childNodes[0]
parent.appendChild(child)
m.mount(parent.querySelector("span"), input)
if (!parent.querySelector("input").checked) {
document.getElementById("fillable-" + c.id).querySelector("input").disabled = true
}
}
document.getElementById("choice-" + c.id)
.childNodes[0].querySelector("input")
.required = true
})
},
view: function(vnode) {
return [
m("div", {
style: {
color: "rgba(0, 0, 0, .4)",
fontSize: "16px",
fontWeight: "400",
lineHeight: "24px",
marginTop: ".5em"
}
}, SectionQuestion.current.data.attributes.text + " *"),
m("i", {
style: {
color: "rgba(0, 0, 0, .4)"
}
}, "(" + SectionQuestion.current.data.attributes.description + ")" || null),
m(RadioGroup, {
id: "choices" + SectionQuestion.current.data.id,
all: {name: SectionQuestion.current.data.attributes.questionType},
className: "flex",
style: {
margin: ".5rem 0",
flexFlow: "row wrap"
},
buttons: SectionQuestion.current.data.attributes.choices.map(function(c) {
return {
id: "choice-" + c.id,
value: c.id,
label: c.text,
defaultChecked: c.id == choice.form.req(),
style: {
marginTop: ".5em",
marginBottom: ".5em",
marginRight: "0",
flexGrow: "1",
flexBasis: "100%"
}
}
}),
onChange: function(state) {
var chosen = _.find(SectionQuestion.current.data.attributes.choices, function(o) { return o.id == state.value })
var target = document.getElementById("fillable-" + chosen.id)
if (chosen.fillable) {
target.querySelector("input").disabled = false
target.querySelector("input").focus()
} else {
SectionQuestion.current.data.attributes.choices.map(function(c) {
var target = document.getElementById("fillable-" + c.id)
if (!_.isNil(target)) {
target.querySelector("input").disabled = true
text.form.req("")
}
})
}
choice.form.req(state.value)
}
})
]
}
}
const bool = {
form: powerform({
req: function(v) {
if (v == null || v == "") {
return "Pilih salah satu jawaban di bawah ini"
}
}
}),
oninit: function() {
var lS = {}
if (!_.isNil(window.localStorage.answers)) {
lS = _.find(JSON.parse(window.localStorage.answers), function(o) {
return o.id == SectionQuestion.current.data.id
})
}
bool.form.req(_.isNil(lS) ? "" : lS.answers[0].choice)
},
view: function() {
return [
m("div", {
style: {
color: "rgba(0, 0, 0, .4)",
fontSize: "16px",
fontWeight: "400",
lineHeight: "24px",
marginTop: ".5em"
}
}, SectionQuestion.current.data.attributes.text + " *"),
m("i", {
style: {
color: "rgba(0, 0, 0, .4)"
}
}, "(" + SectionQuestion.current.data.attributes.description + ")" || null),
m(RadioGroup, {
id: "bool" + SectionQuestion.current.data.id,
all: {name: SectionQuestion.current.data.attributes.questionType},
className: "flex",
style: {
margin: ".5rem 0",
flexFlow: "row wrap"
},
buttons: [{label: "Benar", value: 1}, {label: "Salah", value: 0}].map(function(o) {
return {
id: "true",
label: o.label,
value: o.value,
defaultChecked: o.value == SectionQuestion.current.data.attributes.answer.questionchoice_id,
style: {
marginTop: ".5em",
marginBottom: ".5em",
marginRight: "0",
flexGrow: "1",
flexBasis: "100%"
}
}
}),
onChange: function(state) {
bool.form.req(Boolean(state.value).toString())
}
})
]
}
}
const numeric = {
form: powerform({
req: function(v) {
if (v == null || v == "") {
return "Pertanyaan ini harus dijawab"
} else if (/[^\d]+/.test(v)) {
return "Gunakan angka"
}
}
}),
oninit: function() {
var lS = {}
if (!_.isNil(window.localStorage.answers)) {
lS = _.find(JSON.parse(window.localStorage.answers), function(o) {
return o.id == SectionQuestion.current.data.id
})
}
numeric.form.req(_.isNil(lS) ? "" : lS.answers[0].text)
},
view: function(vnode) {
var attrs = vnode.attrs
var data = attrs.data || {}
return m(TextField, {
id: data.elId || "question" + SectionQuestion.current.data.id,
label: SectionQuestion.current.data.attributes.text,
floatingLabel: true,
help: Section.current.data.attributes.description,
onChange: function(state) {
numeric.form.req(state.value)
},
validate: function() {
return {
valid: numeric.form.req.isValid(),
error: numeric.form.req.error()
}
},
value: numeric.form.req()
})
}
}
const multichoice = {
form: powerform({
req: function(v) {
if (_.isEmpty(v) || _.isNil(v)) {
return "Pilih minimal 1 jawaban"
}
var item = _.find(SectionQuestion.current.data.attributes.choices, function(o) {
return o.fillable
})
if (
_.find(v, function(o) { return o == item.id }) != undefined
&& _.isEmpty(document.getElementById("mfillable-" + item.id)
.querySelector("input").value)
) {
return "Tuliskan jawaban Anda"
}
}
}),
oninit: function() {
var lS = {}
if (!_.isNil(window.localStorage.answers)) {
lS = _.find(JSON.parse(window.localStorage.answers), function(o) {
return o.id == SectionQuestion.current.data.id
})
}
var choices = []
if (!_.isNil(lS)) {
for (var i = 0; i < lS.answers.length; i++) {
choices.push(lS.answers[i].choice)
}
}
multichoice.form.req(choices)
},
oncreate: function(vnode) {
SectionQuestion.current.data.attributes.choices.map(function(c) {
if (c.fillable) {
var child = document.createElement("span")
// child.style.marginTop = "1.4em"
var input = { view: function() {
return m(text, {
data: {
elId: "mfillable-" + c.id,
text: "Tuliskan",
float: false
}
})
}}
/* Get parent */
var parent = document.getElementById("mchoice-" + c.id).childNodes[0]
parent.appendChild(child)
m.mount(parent.querySelector("span"), input)
document.getElementById("mfillable-" + c.id).querySelector("input").disabled = true
}
})
},
view: function(vnode) {
var attrs = vnode.attrs
var data = attrs.data || {}
return [
m("div", {
style: {
color: "rgba(0, 0, 0, .4)",
fontSize: "16px",
fontWeight: "400",
lineHeight: "24px",
marginTop: ".5em"
}
}, SectionQuestion.current.data.attributes.text + " *"),
m("i", {
style: {
color: "rgba(0, 0, 0, .4)"
}
}, "(" + SectionQuestion.current.data.attributes.description + ")" || null),
m(".flex", {
style: {marginTop: "1em", marginBottom: "1em", flexFlow: "row wrap"}
}, SectionQuestion.current.data.attributes.choices.map(function(o) {
return m(Checkbox, {
style: {margin: ".5em 0"},
id: "mchoice-" + o.id,
label: o.text,
value: o.id,
defaultChecked: multichoice.form.req().indexOf(o.id) != -1,
onChange: function(state) {
var choices = multichoice.form.req()
if (state.checked) {
choices.push(state.value)
if (o.fillable) {
var target = document.getElementById("mfillable-" + o.id)
.querySelector("input")
target.disabled = false
target.focus()
}
} else {
var index = _.findIndex(choices, function(o) {
return o == state.value
})
choices.splice(index, 1)
if (o.fillable) {
var target = document.getElementById("mfillable-" + o.id)
.querySelector("input")
target.disabled = true
}
}
multichoice.form.req(choices)
}
})
}))
]
}
}
window.questionType = {text, choice, bool, numeric, multichoice}
const question = {
oninit: function(vnode) {
Respondent.fetch(1)
Section.fetch(vnode.attrs.id)
SectionQuestion.fetch(vnode.attrs.id)
},
view: function() {
return [
m(".header-img", {
style: {
backgroundImage: "url('img/head1.jpg')"
}
}),
m(".header-content", {
style: {top: 0}
}, m("article", {
style: {backgroundColor: "#fff", minHeight: "100vh"}
}, Section.loading ? null : [
m("h2.article-title", [
m("i.fa.fa-hashtag[aria-hidden=true]", {
style: {color: "rgb(255, 153, 0)", cursor: "pointer"},
onclick: function() {
m.route.set("/questionnaires/" + Section.current.data.attributes.questionnaire.id)
}
}),
m("div", {
style: {marginTop: ".3em"}
}, Section.current.data.attributes.title),
]),
_.isNil(Section.current.data.description) ? null : m("h6.article-title", "(" + Section.current.data.attributes.description + ")"),
SectionQuestion.loading ? null : m("h4.article-title", m("div", m("span", {style: {flexGrow: "1"}}, [
"Nomor: ",
m("input", {
placeholder: SectionQuestion.current.meta.pagination.current_page,
style: {
maxWidth: "3em",
minHeight: "3em"
},
maxlength: SectionQuestion.current.meta.pagination.total_pages.toString().length,
onchange: function(e) {
// if (e.keyCode == 13 || e.which == 13 || e.key == "Enter") {
var value = this.value
var question = _.find(Section.current.data.attributes.questions, function(o) {
return o.number == value
})
if (!_.isNil(question)) {
SectionQuestion.nextOrPrev(
SectionQuestion.current
.data.attributes.
section.links.self
+ "/questions?page=" + question.number
)
}
// }
}
}),
"/",
SectionQuestion.current.meta.pagination.total_pages
]))),
SectionQuestion.loading ? null : m(".flex", {
style: {flexFlow: "row wrap"}
}, m(".constant"), m(Card, {
style: {flexBasis: "80%"},
content: [
{
text: {
content: m("form#question-form", {
onsubmit: function(e) {
e.preventDefault()
}
}, [
m(window.questionType[SectionQuestion.current.data.attributes.questionType]),
m(".flex", [
m(Button, {
id: "prev",
label: [
m("i.fa.fa-chevron-left.fa-fw[aria-hidden=true]"),
m.trust("&nbsp;"),
"prev"
],
style: {
backgroundColor: "rgb(255, 153, 0)",
padding: ".8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre"
},
tone: "dark",
events: {
onclick: function() {
var qType =
SectionQuestion.current
.data.attributes
.questionType
if (window.questionType[qType].form.isValid()) {
var strQuestions = window.localStorage.getItem("answers")
var questions = JSON.parse(strQuestions) || []
var question = {
id: SectionQuestion.current.data.id,
answers: []
}
if (qType == "multichoice") {
var choices =
window.questionType[qType]
.form.req()
for (var i = 0; i < choices.length; i++) {
var answer = {}
answer.choice = choices[i]
answer.text =
window.questionType["text"]
.form.req()
answer.respondent = {
id: Respondent.current.data.id,
name: Respondent.current.data.attributes.name,
occupation: Respondent.current.data.attributes.occupation,
gender: Respondent.current.data.attributes.gender
}
answer.question = {
id: SectionQuestion.current.data.id,
text: SectionQuestion.current.data.attributes.text,
description: SectionQuestion.current.data.attributes.description,
section: {
id: Section.current.data.id,
title: Section.current.data.attributes.title,
description: Section.current.data.attributes.description
}
}
question.answers
.push(answer)
}
} else {
var answer = {
respondent: {
id: Respondent.current.data.id,
name: Respondent.current.data.attributes.name,
occupation: Respondent.current.data.attributes.occupation,
gender: Respondent.current.data.attributes.gender
},
question: {
id: SectionQuestion.current.data.id,
text: SectionQuestion.current.data.attributes.text,
description: SectionQuestion.current.data.attributes.description,
section: {
id: Section.current.data.id,
title: Section.current.data.attributes.title,
description: Section.current.data.attributes.description
}
}
}
if (qType == "choice" || qType == "bool") {
var choice = window.questionType[qType]
.form.req()
answer.choice = choice
answer.text = window.questionType["text"].form.req()
} else {
var text = window.questionType[qType]
.form.req()
answer.choice = null
answer.text = text
}
question.answers
.push(answer)
}
var dupIndex =
_.findIndex(questions, function(o) {
return o.id == SectionQuestion.current.data.id
})
if (dupIndex == -1) questions.push(question)
else questions[dupIndex] = question
window.localStorage
.setItem(
"answers",
JSON.stringify(questions)
)
}
if (!_.isNil(SectionQuestion.current.links.prev)) {
SectionQuestion.nextOrPrev(SectionQuestion.current.links.prev)
}
}
}
}),
m(".flex"),
!_.isNil(window.localStorage.getItem("answers"))
&& JSON.parse(window.localStorage.getItem("answers")).length
== SectionQuestion.current.meta.pagination.total
&& SectionQuestion.current.meta.pagination.current_page
== SectionQuestion.current.meta.pagination.total_pages ?
m(Button, {
id: "finish",
label: [
"finish",
m.trust("&nbsp;"),
m("i.fa.fa-check.fa-fw[aria-hidden=true]")
],
style: {
backgroundColor: "rgb(255, 153, 0)",
padding: ".8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre"
},
tone: "dark",
events: {
onclick: function() {
var arrAnswers = JSON.parse(window.localStorage.getItem("answers"))
// var answers = []
for (var i = 0; i < arrAnswers.length; i++) {
for (var o = 0; o < arrAnswers[i].answers.length; o++) {
// answers.push(arrAnswers[i].answers[o])
QuestionAnswer.current = arrAnswers[i].answers[o]
QuestionAnswer.upload(QuestionAnswer.current.question.id)
}
}
// console.log(answers);
console.log("finished");
}
}
})
: m(Button, {
id: "next",
label: [
"next",
m.trust("&nbsp;"),
m("i.fa.fa-chevron-right.fa-fw[aria-hidden=true]")
],
style: {
backgroundColor: "rgb(255, 153, 0)",
padding: ".8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre"
},
tone: "dark",
events: {
onclick: function() {
console.log(JSON.parse(window.localStorage.getItem("answers")).length);
var qType =
SectionQuestion.current
.data.attributes
.questionType
if (window.questionType[qType].form.isValid()) {
var strQuestions = window.localStorage.getItem("answers")
var questions = JSON.parse(strQuestions) || []
var question = {
id: SectionQuestion.current.data.id,
answers: []
}
if (qType == "multichoice") {
var choices =
window.questionType[qType]
.form.req()
for (var i = 0; i < choices.length; i++) {
var answer = {}
answer.choice = choices[i]
answer.text =
window.questionType["text"]
.form.req()
answer.respondent = {
id: Respondent.current.data.id,
name: Respondent.current.data.attributes.name,
occupation: Respondent.current.data.attributes.occupation,
gender: Respondent.current.data.attributes.gender
}
answer.question = {
id: SectionQuestion.current.data.id,
text: SectionQuestion.current.data.attributes.text,
description: SectionQuestion.current.data.attributes.description,
section: {
id: Section.current.data.id,
title: Section.current.data.attributes.title,
description: Section.current.data.attributes.description
}
}
question.answers
.push(answer)
}
} else {
var answer = {
respondent: {
id: Respondent.current.data.id,
name: Respondent.current.data.attributes.name,
occupation: Respondent.current.data.attributes.occupation,
gender: Respondent.current.data.attributes.gender
},
question: {
id: SectionQuestion.current.data.id,
text: SectionQuestion.current.data.attributes.text,
description: SectionQuestion.current.data.attributes.description,
section: {
id: Section.current.data.id,
title: Section.current.data.attributes.title,
description: Section.current.data.attributes.description
}
}
}
if (qType == "choice" || qType == "bool") {
var choice = window.questionType[qType]
.form.req()
answer.choice = choice
answer.text = window.questionType["text"].form.req()
} else {
var text = window.questionType[qType]
.form.req()
answer.choice = null
answer.text = text
}
question.answers
.push(answer)
}
var dupIndex =
_.findIndex(questions, function(o) {
return o.id == SectionQuestion.current.data.id
})
if (dupIndex == -1) questions.push(question)
else questions[dupIndex] = question
window.localStorage
.setItem(
"answers",
JSON.stringify(questions)
)
}
if (!_.isNil(SectionQuestion.current.links.next)) {
SectionQuestion.nextOrPrev(SectionQuestion.current.links.next)
}
}
}
})
])
])
}
}
]
}), m(".constant"))
]))
]
}
}
export default question

View File

@@ -0,0 +1,65 @@
import m from "mithril"
import { Card, RaisedButton } from "polythene-mithril"
import Questionnaire from "../../models/Questionnaire"
import QuestionnaireSection from "../../models/QuestionnaireSection"
export const questionnaire = {
oninit: function(vnode) {
window.scrollTo(0, 0)
if (
_.isEmpty(QuestionnaireSection.current)
|| _.isNil(QuestionnaireSection.current)
|| _.isEmpty(Questionnaire.current)
|| _.isNil(Qustionnaire.current)
) {
Questionnaire.fetch(vnode.attrs.id)
QuestionnaireSection.fetch(vnode.attrs.id)
}
},
view: function() {
return [
m(".header-img", {
style: {
backgroundImage: "url('img/head1.jpg')"
}
}),
m(".header-content", {
style: {top: 0}
}, m("article", {
style: {backgroundColor: "#fff"}
}, QuestionnaireSection.loading || Questionnaire.loading ? null : [
m("h2.article-title", [
m("i.fa.fa-book[aria-hidden=true]", {
style: {color: "rgb(255, 153, 0)", cursor: "pointer"},
onclick: function() {
m.route.set('/questionnaires/')
}
}),
m("div", {
style: {marginTop: ".3em"}
}, Questionnaire.current.data.attributes.title)
]),
m(".flex", {
style: {flexFlow: "row wrap"}
}, QuestionnaireSection.current.data.map(function(o) {
return m(Card, {
style: {width: "100%"},
content: [
{
primary: {
title: m("a", {
style: {cursor: "pointer"},
onclick: function() {
m.route.set("/sections/" + o.id)
}
}, o.title),
// subtitle: o.description.length > 56 ? o.description.substr(0, 50) + " ..." : o.description
}
}
]
})
}))
]))
]
}
}

View File

@@ -0,0 +1,136 @@
import m from "mithril"
import { Card, Shadow } from "polythene-mithril"
import Questionnaire from "../../models/Questionnaire"
export const questionnaireList = {
oninit: function() {
Questionnaire.loadList()
},
view: function() {
return [
m(".header-img", {
style: {
backgroundImage: "url('img/head1.jpg')"
}
}),
m(".header-title#header-top", {
style: {
display: "table",
color: "#fff",
position: "fixed"
}
}, m("div", {
style: {
display: "table-cell",
verticalAlign: "middle",
textAlign: "center"
}
}, [
m("h1", {
style: {
fontWeight: "bold"
}
}, m("span", "Questionnaire List")),
m("p", "Daftar kuesioner yang dapat Anda isi"),
m("div", {
style: {padding: "3em 0"}
}),
m("span.fa-stack.fa-2x", {
id: "down",
style: {cursor: "pointer"},
onclick: function() {
var scrollValue = 1
var scrolling = setInterval(function() {
window.scrollTo(0, window.scrollY + scrollValue)
if (
window.pageYOffset
>= document.querySelector(".header-title").offsetHeight
|| window.pageYOffset
>= document.querySelector("article").offsetHeight
) {
window.clearInterval(scrolling)
}
scrollValue++
}, 10)
},
onmouseover: function() {
this.childNodes[0]
.style.color = "#fff"
this.childNodes[1]
.style.transform = "translateY(0.15em)"
this.childNodes[1]
.style.color = "#000"
},
onmouseout: function() {
this.childNodes[0]
.style.color = "rgba(0, 0, 0, .4)"
this.childNodes[1]
.style.transform = "translateY(0)"
this.childNodes[1]
.style.color = "#fff"
},
oncreate: function() {
document.getElementById("down")
.childNodes[0].style.color = "rgba(0, 0, 0, .4)"
document.getElementById("down")
.childNodes[1].style.color = "#fff"
}
}, [
m("i.fa.fa-circle.fa-stack-2x", {
style: {
transition: "all .3s ease .05s",
webkitTransition: "all .3s ease .05s",
mozTransition: "all .3s ease .05s",
oTransition: "all .3s ease .05s"
},
}),
m("i.fa.fa-angle-double-down.fa-stack-1x", {
style: {
transition: "all .3s ease .05s",
webkitTransition: "all .3s ease .05s",
mozTransition: "all .3s ease .05s",
oTransition: "all .3s ease .05s"
}
})
])
])),
m(".header-content", m("article", {
style: {backgroundColor: "#fff"}
}, [
m("h2.article-title", [
m("i.fa.fa-graduation-cap[aria-hidden=true]", {
style: {color: "rgb(255, 153, 0)"}
}),
m("div", {
style: {marginTop: ".3em"}
}, "Mahasiswa STIE BISMA LEPISI")
]),
m(".flex", {
style: {flexFlow: "row wrap"}
}, Questionnaire.loading ? null : Questionnaire.list.map(function(o) {
return m(Card, {
style: {width: "100%"},
before: m(Shadow),
content: [
{
primary: {
title: m("a", {
style: {cursor: "pointer"},
onclick: function() {
m.route.set("/questionnaires/" + o.id)
}
}, o.title),
// subtitle: o.description.length > 56 ?
// o.description.substr(0, 50) + " ..."
// : o.description
subtitle: o.description
}
}
]
})
// }
}))
]))
]
}
}