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

438
assets/js/components/auth.js vendored Normal file
View File

@@ -0,0 +1,438 @@
import m from "mithril"
import moment from "moment"
import DatePicker from "../custom/mithril-datepicker"
import {} from "../../css/custom/mithril-datepicker.css"
import { Card, TextField, RadioButton, RadioGroup, RaisedButton, List, ListTile, Menu, Dialog } from "polythene-mithril"
// import { User } from "../models/User"
const head = {
view: function() {
return [
m(".header-nav", {
style: {
color: "#fff",
cursor: "pointer"
},
onclick: function() {
m.route.set("")
}
}, m("i.fa.fa-home.fa-lg")),
m(".header-img", {
style: {
backgroundImage: "url('img/head1.jpg')"
}
})
]
}
}
export const login = {
isValid: {},
view: function() {
return [
m(head),
m(".header-title", {
style: {
display: "table"
}
}, m("div", {
style: {
display: "table-cell",
verticalAlign: "middle"
}
}, m(".flex", [
m(".constant"),
m(Card, {
className: "front-card",
style: {
width: "initial"
},
content: [
{
primary: {
title: "Masuk",
subtitle: "Masuk dengan kode konfirmasi yang telah diterima"
}
},
{
text: {
content: [
m(TextField, {
label: "Kode",
required: true,
floatingLabel: true,
tight: true,
validate: function(value) {
if (/^[A-Z0-9]+$/.test(value) == false || value.length != 6) {
login.isValid.code = false
return {
valid: false,
error: "Kode tidak valid"
}
} else {
login.isValid.code = true
}
},
validateOnInput: true
})
]
}
},
{
actions: {
content: m(RaisedButton, {
label: "Masuk",
events: {
onclick: function() {
login.isValid.code == true ?
m.route.set("")
: null
}
}
})
}
}
]
}),
m(".constant")
])))
]
}
}
export const register = {
showMenu: false,
oninit: function() {
// if (_.isEmpty(User.current)) return m.route.set("/")
},
view: function() {
return [
m(head),
m(".header-title", {
style: {
display: "table"
}
}, m("form", {
onsubmit: function(e) {
e.preventDefault()
// console.log(User.current);
m.route.set("/questionnaires")
},
style: {
padding: "1em",
display: "table",
height: "100%",
width: "100%"
}
}, m("div", {
style: {
display: "table-cell",
verticalAlign: "middle",
}
}, m(".flex", {
style: {
width: "100%",
}
}, m(".constant"), m(Card, {
className: "front-card",
style: {
height: "100%",
margin: "0"
},
content: [
{
primary: {
title: "Daftar",
subtitle: "Silahkan isi data diri Anda terlebih dahulu"
}
},
{
text: {
className: "flex but",
content: [
m("div", {
style: {
flexBasis: "45%"
}
}, [
m(TextField, {
className: "firstInput",
label: "Nama Lengkap",
required: true,
floatingLabel: true,
tight: true,
autofocus: true,
value: User.current.name,
events: {
oninput: function() {
User.current.name = this.value
}
}
}),
m("span", {
style: {
color: "rgba(0, 0, 0, .4)",
fontSize: "16px",
fontWeight: "400",
lineHeight: "24px"
}
}, "Jenis Kelamin *"),
m(RadioGroup, {
id: "gender",
name: "gender",
style: {
margin: ".5rem 0"
},
buttons: [
{
id: "gender-m",
value: "m",
label: "Laki-laki",
events: {
oncreate: function() {
document.getElementById("gender-m")
.querySelector("input")
.required = "required"
}
}
},
{
id: "gender-f",
value: "f",
label: "Perempuan",
events: {
oncreate: function() {
document.getElementById("gender-f")
.querySelector("input")
.required = "required"
}
}
}
],
onChange: function(state) {
User.current.gender = state.value
}
}),
m("div", {
style: {
color: "rgba(0, 0, 0, .4)",
fontSize: "16px",
fontWeight: "400",
lineHeight: "24px",
marginBottom: ".5em"
}
}, "Tanggal Lahir *"),
m(DatePicker, {
date: User.current.birthDate,
locale: "id-id",
onchange: function(chosenDate) {
User.current.birthDate = moment(chosenDate).format("YYYY-MM-DD HH:mm:ss")
},
oncreate: function() {
var target = document.querySelector(".mithril-date-picker")
var click = target.childNodes[0].onclick
var className = target.childNodes[0].className
return m.mount(target, {
oncreate: function() {
User.current.birthDate = moment().format("YYYY-MM-DD HH:mm:ss")
},
view: function() {
return m("input", {
className: className,
value: moment(User.current.birthDate)
.format("ddd, DD MMM YYYY"),
onclick: click,
required: "required",
readonly: "readonly",
})
}
})
}
})
]),
m("div", {
style: {
flexGrow: "1"
}
}),
m("div", {
style: {
flexBasis: "45%"
}
}, [
m(TextField, {
label: "No. Handphone",
required: true,
floatingLabel: true,
tight: true,
pattern: "[0-9]+",
validateOnInput: true,
error: "Gunakan angka",
events: {
oninput: function() {
User.current.handphone = this.value
}
},
value: User.current.handphone
}),
m(TextField, {
className: "lastInput",
label: "Pekerjaan",
required: true,
floatingLabel: true,
tight: true,
events: {
oninput: function() {
User.current.occupation = this.value
}
},
value: User.current.occupation
}),
m(TextField, {
id: "category",
label: "Kategori",
required: true,
events: {
onfocus: function() {
var holder = document
.querySelector("span.pe-dialog__placeholder")
Dialog.show({
title: "Pilih kategori",
body: m(List, {
tiles: [
{
title: "Mahasiswa STIE BISMA LEPISI",
value: 43,
hoverable: true
},
{
title: "Mahasiswa AKSEMA LEPISI",
value: 44,
hoverable: true
},
{
title: "Dosen STIE BISMA LEPISI",
value: 45,
hoverable: true
},
{
title: "Dosen AKSEMA LEPISI",
value: 46,
hoverable: true
}
],
keyboardControl: true,
highlightIndex: 0,
onSelect: function({attrs}) {
Dialog.hide()
User.current.category = attrs.value
document.getElementById("category")
.querySelector("input")
.value = attrs.title
document.getElementById("category")
.className += "pe-textfield--dirty"
}
}),
backdrop: true
})
}
}
})
])
]
}
},
{
actions: {
content: m(RaisedButton, {
element: "button",
label: "Kirim",
type: "submit"
})
}
}
]
}), m(".constant"))))),
m(Dialog)
]
}
}
export const loginUser = {
view: function() {
return [
m(head),
m(".header-title", {
style: {
display: "table"
}
}, m("div", {
style: {
display: "table-cell",
verticalAlign: "middle"
}
}, m(".flex", [
m(".constant"),
m("form", {
onsubmit: function(e) {
e.preventDefault()
User.login()
}
}, m(Card, {
className: "front-card",
style: {
width: "initial"
},
content: [
{
primary: {
title: "Masuk"
}
},
{
text: {
className: "login-scroll",
content: [
m(TextField, {
label: "Username",
required: true,
pattern: "[a-zA-Z0-9]+",
floatingLabel: true,
tight: true,
autofocus: true,
validateOnInput: true,
value: User.current.username,
onChange: function(state) {
User.current.username = state.value
}
}),
m(TextField, {
label: "Password",
type: "password",
required: true,
floatingLabel: true,
tight: true,
value: User.current.password,
onChange: function(state) {
User.current.password = state.value
}
})
]
}
},
{
actions: {
content: m(RaisedButton, {
element: "button",
label: "Masuk",
type: "submit"
})
}
}
]
})),
m(".constant")
])))
]
}
}

124
assets/js/components/beta/menuList.js vendored Normal file
View File

@@ -0,0 +1,124 @@
import m from "mithril"
import stream from "mithril/stream"
import {
Toolbar,
ToolbarTitle,
Shadow,
List,
ListTile,
Search,
IconButton
} from "polythene-mithril"
import Dept from "../../models/beta/Dept"
const barsIcon = "<svg width=\"1792\" height=\"1792\" viewBox=\"0 0 1792 1792\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M1664 1344v128q0 26-19 45t-45 19h-1408q-26 0-45-19t-19-45v-128q0-26 19-45t45-19h1408q26 0 45 19t19 45zm0-512v128q0 26-19 45t-45 19h-1408q-26 0-45-19t-19-45v-128q0-26 19-45t45-19h1408q26 0 45 19t19 45zm0-512v128q0 26-19 45t-45 19h-1408q-26 0-45-19t-19-45v-128q0-26 19-45t45-19h1408q26 0 45 19t19 45z\" fill=\"#fff\"/></svg>"
const backIcon = "<svg width=\"1792\" height=\"1792\" viewBox=\"0 0 1792 1792\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M1664 896v128q0 53-32.5 90.5t-84.5 37.5h-704l293 294q38 36 38 90t-38 90l-75 76q-37 37-90 37-52 0-91-37l-651-652q-37-37-37-90 0-52 37-91l651-650q38-38 91-38 52 0 90 38l75 74q38 38 38 91t-38 91l-293 293h704q52 0 84.5 37.5t32.5 90.5z\"/></svg>"
const searchIcon = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z\"/></svg>"
const searchBox = {
view: function() {
return m(Search, {
textfield: {label: "Search"},
buttons: {
none: {
after: m(IconButton, {
icon: {svg: m.trust(searchIcon)},
inactive: true
})
}
}
})
}
}
const menuList = {
oninit: function(vnode) {
const show = stream(false)
vnode.state = {
show
}
},
view: function(vnode) {
const state = vnode.state
const show = state.show()
return m("div", [
m(Toolbar, {
style: {
position: "fixed",
zIndex: "11",
width: "100%",
backgroundColor: "rgba(255, 255, 255, .93)"
}
}, [
m("#bars", {
style: {cursor: "pointer", display: "inline-block", marginLeft: "1em"},
onclick: function() {
this.classList.toggle("change")
state.show(!state.show())
}
}, [
m(".bar1"),
m(".bar2"),
m(".bar3")
]),
m(ToolbarTitle, {
text: vnode.attrs.title
})
]),
m("#menu", {
style: {
left: show ? "0" : "-100%"
}
}, [
m(Shadow),
m(List, {
id: "menu-list",
tiles: [
m(ListTile, {
title: "All Users",
hoverable: true,
events: {
onclick: function() {
m.route.set("/beta/users")
}
}
}),
m(ListTile, {
header: true,
title: "Department List"
}),
vnode.attrs.list.map(function(o) {
return m(ListTile, {
title: o.name,
hoverable: true,
events: {
onclick: function() {
state.show(false)
document.getElementById("bars")
.classList.toggle("change")
m.route.set("/beta/departments/" + o.id)
}
}
})
})
]
})
]),
m("#menu-overlay", {
style: {
opacity: ".4",
display: show ? "block" : "none"
},
onclick: function() {
if (show) {
state.show(false)
document.getElementById("bars")
.classList.toggle("change")
}
}
})
])
}
}
export default menuList

316
assets/js/components/beta/userList.js vendored Normal file
View File

@@ -0,0 +1,316 @@
import m from "mithril"
import stream from "mithril/stream"
import {
Card,
ListTile,
Icon,
Search,
Shadow,
IconButton
} from "polythene-mithril"
import menuList from "./menuList"
import Dept from "../../models/beta/Dept"
import User from "../../models/beta/User"
const angleDownIcon = "<svg width=\"1792\" height=\"1792\" viewBox=\"0 0 1792 1792\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M1395 736q0 13-10 23l-466 466q-10 10-23 10t-23-10l-466-466q-10-10-10-23t10-23l50-50q10-10 23-10t23 10l393 393 393-393q10-10 23-10t23 10l50 50q10 10 10 23z\"/></svg>"
const searchIcon = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z\"/></svg>"
const clearIcon = "<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\">"
export const userList = {
view: function(vnode) {
Dept.current = _.find(Dept.list, function(d) {return d.id == vnode.attrs.id})
Dept.current.users = _.filter(User.list, function(u) {return u.dept == Dept.current.id})
return [
m(menuList, {title: Dept.current.name, list: Dept.list}),
m(".wrapper-body", {
style: {
display: "flex",
flexFlow: "row wrap",
margin: "0 auto",
paddingTop: "64px"
}
}, _.filter(Dept.current.users, function(u) {return u.super}).map(function(user) {
return m(superList, {user})
}))
]
}
}
export const userAll = {
oninit: function(vnode) {
var show = stream(false)
var search = ""
vnode.state = {show, search}
},
view: function(vnode) {
var state = vnode.state
var show = state.show()
var search = state.search
return [
m(menuList, {title: "User List", list: Dept.list}),
m(".wrapper-body", {
style: {
display: "flex",
flexFlow: "row wrap",
margin: "0 auto",
paddingTop: "64px"
}
}, [
m(Search, {
style: {
margin: "1em"
},
textfield: {
label: "Search",
value: state.search,
onChange: function({value}) {
state.search = value
}
},
before: m(Shadow),
buttons: {
none: {
before: m(IconButton, {
icon: {svg: m.trust(searchIcon)},
inactive: true
}),
after: m(IconButton, {
icon: {svg: m.trust(clearIcon)},
events: {
onclick: function() {
state.search = ""
}
}
})
},
focus: {
before: m(IconButton, {
icon: {svg: m.trust(searchIcon)},
inactive: true
}),
after: m(IconButton, {
icon: {svg: m.trust(clearIcon)},
events: {
onclick: function() {
state.search = ""
}
}
})
},
dirty: {
before: m(IconButton, {
icon: {svg: m.trust(searchIcon)},
inactive: true
}),
after: m(IconButton, {
icon: {svg: m.trust(clearIcon)},
events: {
onclick: function() {
state.search = ""
}
}
})
},
focus_dirty: {
before: m(IconButton, {
icon: {svg: m.trust(searchIcon)},
inactive: true
}),
after: m(IconButton, {
icon: {svg: m.trust(clearIcon)},
events: {
onclick: function() {
state.search = ""
}
}
})
}
}
}),
User.list.map(function(user) {
return m(superList, {user})
})
])
]
}
}
const superList = {
oninit: function(vnode) {
var show = stream(false)
vnode.state = {show}
},
view: function(vnode) {
var state = vnode.state
var show = state.show()
var user = vnode.attrs.user
return m(Card, {
style: {
flexBasis: "100%",
webkitTransition: "all .2s cubic-bezier(0, 0, .6, 1)",
mozTransition: "all .2s cubic-bezier(0, 0, .6, 1)",
oTransition: "all .2s cubic-bezier(0, 0, .6, 1)",
transition: "all .2s cubic-bezier(0, 0, .6, 1)",
},
content: [{
text: {
content: [
m(ListTile, {
front: m(Icon, {
avatar: true,
size: "large",
src: "../../img/yayasan.png"
}),
title: user.name,
subContent: show ? m("div", {
style: {fontSize: "smaller", marginTop: "1em"}
}, [
m("div", [
"Alamat: ",
user.address
]),
m("div", [
"TTL: ",
user.birth
]),
m("div", [
"Telp.: ",
user.phone
]),
m("div", [
"Email: ",
user.mail
]),
m("div", [
"Tgl. Masuk: ",
user.workEntry
]),
m("div", [
"Lama Kerja: ",
user.workPeriod
]),
m("div", [
"Pendidikan: ",
user.education
])
]) : null
}),
m("div", {
style: {textAlign: "center"}
}, m(Icon, {
element: "a",
svg: {content: m.trust(angleDownIcon), style: {color: "rgb(0, 145, 234)"}},
style: {
// opacity: ".5",
cursor: "pointer",
borderRadius: "50%",
transform: show ? "rotateX(180deg)" : "rotateX(0)",
webkitTransition: "all .25s linear",
mozTransition: "all .25s linear",
oTransition: "all .25s linear",
transition: "all .25s linear"
},
events: {
onclick: function() {
state.show(!state.show())
}
}
})),
show ? _.filter(
Dept.current.users,
function(u) {return !u.super}
).map(function(staff) {return m(staffList, {staff})}) : null
]
}
}]
})
}
}
const staffList = {
oninit: function(vnode) {
var peek = stream(false)
vnode.state = {peek}
},
view: function(vnode) {
var state = vnode.state
var peek = state.peek()
var staff = vnode.attrs.staff
return m(Card, {
style: {
width: "100%",
webkitTransition: "all .1s cubic-bezier(0, 0, .6, 1)",
mozTransition: "all .1s cubic-bezier(0, 0, .6, 1)",
oTransition: "all .1s cubic-bezier(0, 0, .6, 1)",
transition: "all .1s cubic-bezier(0, 0, .6, 1)",
},
content: [{
text: {
content: [
m(ListTile, {
front: m(Icon, {
avatar: true,
size: "large",
src: "../../img/yayasan.png"
}),
title: staff.name,
subContent: peek ? m("div", {
style: {fontSize: "smaller", marginTop: "1em"}
}, [
m("div", [
"Alamat: ",
staff.address
]),
m("div", [
"TTL: ",
staff.birth
]),
m("div", [
"Telp.: ",
staff.phone
]),
m("div", [
"Email: ",
staff.mail
]),
m("div", [
"Tgl. Masuk: ",
staff.workEntry
]),
m("div", [
"Lama Kerja: ",
staff.workPeriod
]),
m("div", [
"Pendidikan: ",
staff.education
])
]) : null
}),
m("div", {
style: {textAlign: "center"}
}, m(Icon, {
element: "a",
svg: {content: m.trust(SVGAngleDown)},
style: {
opacity: ".5",
cursor: "pointer",
borderRadius: "50%",
transform: peek ? "rotateX(180deg)" : "rotateX(0)",
webkitTransition: "all .25s linear",
mozTransition: "all .25s linear",
oTransition: "all .25s linear",
transition: "all .25s linear"
},
events: {
onclick: function() {
state.peek(!state.peek())
}
}
}))
]
}
}]
})
}
}

79
assets/js/components/buttons.js vendored Normal file
View File

@@ -0,0 +1,79 @@
import m from "mithril"
import { Button} from "polythene-mithril"
import { ButtonCSS } from "polythene-css"
ButtonCSS.addStyle(".bordered-button", {
color_light_text: "#03a9f4",
color_light_border: "#03a9f4",
color_dark_text: "#03a9f4",
color_dark_border: "#03a9f4",
})
const buttonTextStyle = {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre"
}
export const editButton = {
view: function(vnode) {
return m(Button, {
id: "editBtn",
style: buttonTextStyle,
element: "div",
className: "bordered-button absolute-button",
borders: true,
label: [m("i.fa.fa-edit.fa-fw"), m.trust("&nbsp;"), m("span", "Ubah")],
events: {
onclick: function() {
m.route.set(vnode.attrs.redirectURL)
}
}
})
}
}
export const seeButton = {
view: function(vnode) {
return m(Button, {
style: buttonTextStyle,
label: [m("i.fa.fa-eye.fa-fw"), m.trust("&nbsp;"), m("span", "Lihat")],
borders: true,
className: "bordered-button",
events: {
onclick: function() {
/* Request ke section model */
// sModel.fetch(s.url)
/* Route */
m.route.set(vnode.attrs.redirectURL)
}
}
})
}
}
export const backButton = {
view: function() {
return m("span", {
style: {
fontSize: "14px",
textTransform: "uppercase",
whiteSpace: "pre"
}
}, m("i.fa.fa-arrow-left.fa-fw"), m.trust("&nbsp;"), m("span", "Kembali"))
}
}
export const logoutButton = {
view: function() {
return m("span", {
style: {
fontSize: "14px",
textTransform: "uppercase"
}
}, m("i.fa.fa-sign-out.fa-fw"), m.trust("&nbsp;"), m("span", "Keluar"))
}
}

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
}
}
]
})
// }
}))
]))
]
}
}

651
assets/js/components/editQuestion.js vendored Normal file
View File

@@ -0,0 +1,651 @@
import m from "mithril"
import moment from "moment"
import _ from "lodash"
import powerform from "powerform"
import { Card, Button, RaisedButton, TextField, RadioGroup, RadioButton, Checkbox, Dialog } from "polythene-mithril"
// import DatePicker from "../custom/mithril-datepicker"
import {} from "../../css/custom/mithril-datepicker.css"
import { nav } from "./nav"
import Question from "../models/Question"
var viewChoice = {
view: function(vnode) {
var data = vnode.attrs.data
return [
m(Card, {
style: {
width: "100%",
flexGrow: "1",
paddingTop: "1.5em"
},
content: [
{
text: {
content: [
m("i.fa.fa-times.fa-fw#remove" + data.id, {
style: {
position: "absolute",
top: "0",
right: "0",
cursor: "pointer"
}
}),
Question.current.questionType == "multichoice" ?
m(Checkbox, {
className: "choice-view",
label: data.text
})
: m(RadioButton, {
className: "choice-view",
label: data.text
}),
data.fillable ?
m(TextField, {
label: "Isikan jawaban anda",
required: true,
tight: true
})
: null
]
}
}
],
events: {
onclick: function(e) {
var parent = this.parentNode
if (e.target != document.querySelector("#remove" + data.id)) {
m.mount(parent, {
view: function() {
return m(editChoice, {data: data, parent: parent})
}
})
} else {
Dialog.show({
body: [
m(".pe-dialog-pane__title", "Hapus pilihan"),
m("div", "Pilihan ini akan dihapus setelah klik pada tombol 'Simpan'.")
],
footerButtons: [
m(Button, {
label: "Konfirmasi",
events: {
onclick: function() {
parent.removeChild(parent.childNodes[0])
Dialog.hide()
}
}
}),
m(Button, {
label: "Batal",
events: {
onclick: function() {
Dialog.hide()
}
}
})
],
backdrop: true
})
}
}
}
})
]
}
}
var Choices = {
data: [],
oninit: function(vnode) {
Choices.data = vnode.attrs.data
},
view: function() {
return [
m(Checkbox, {
label: "Dapat pilih lebih dari 1",
checked: Question.current.questionType == "multichoice" ?
true : false,
onChange: function(state) {
state.checked ?
Question.current.questionType = "multichoice"
: Question.current.questionType = "choice"
}
}),
_.isEmpty(Choices.data) ?
m(".flex#question-new", m(newChoice))
: [
Choices.data.map(function(choice) {
var id = ".flex"
return m(id, m(viewChoice, {data: choice}))
}),
m(Dialog),
m(plusButton)
]
]
}
}
var plusButton = {
view: function() {
return m(".flex#choice-new", m(Button, {
className: "flex",
label: [
m("i.fa.fa-plus.fa-fw"),
m.trust("&nbsp;"),
"Tambah"
],
style: {
padding: ".8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
transition: ".2s all ease"
},
events: {
onmouseover: function() {
this.childNodes[0].style.backgroundColor = "rgba(255, 255, 255, .8)"
},
onmouseout: function() {
this.childNodes[0].style.backgroundColor = "#fff"
},
onclick: function() {
m.mount(document.getElementById("choice-new"), {
view: function() {
return m(newChoice)
}
})
}
}
}))
}
}
var editChoice = {
oncreate: function() {
var target = document.getElementsByClassName("choices")
for (var i = 0; i < target.length; i++) {
target[i].querySelector(".pe-card__content").style.width = "100%"
}
},
view: function(vnode) {
var data = vnode.attrs.data
return [
m("div", {
style: {
flexGrow: "1"
}
}), m(Card, {
className: "choices",
style: {
width: "100%",
flexGrow: "1"
},
content: [
{
text: {
content: [
m(".flex", m(TextField, {
label: "Teks",
required: true,
floatingLabel: true,
tight: true,
value: data.text,
events: {
oninput: m.withAttr("value", function(value) {
data.text = value
})
}
}), m("div", m.trust("&nbsp;")), m(Checkbox, {
style: {
marginTop: "2.5em",
flexBasis: "25%"
},
label: "Dapat diisi",
checked: data.fillable,
onChange: function(state) {
data.fillable = state.checked
}
})),
m(".flex", [
m(TextField, {
label: "Deskripsi",
floatingLabel: true,
tight: true,
value: data.description,
events: {
oninput: m.withAttr("value", function(value) {
data.description = value
})
}
})
]),
m("div", {
style: {
textAlign: "right"
}
}, [
m(RaisedButton, {
label: [
m("i.fa.fa-check.fa-fw"),
m.trust("&nbsp;"),
"Simpan"
],
tone: "dark",
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "#009933"
},
events: {
onclick: function() {
m.mount(
vnode.attrs.parent,
{
view: function() {
return m(viewChoice, {data: data})
}
}
)
}
}
}),
m(RaisedButton, {
label: [
m("i.fa.fa-times.fa-fw"),
m.trust("&nbsp;"),
"Batal"
],
tone: "dark",
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "#ff0000"
},
events: {
onclick: function() {
m.mount(
vnode.attrs.parent,
{
view: function() {
return m(viewChoice, {data: data})
}
}
)
}
}
})
])
]
}
}
]
}), m("div", {
style: {
flexGrow: "1"
}
})
]
}
}
var newChoice = {
data: {},
oninit: function() {
newChoice.data = {}
},
oncreate: function() {
var target = document.getElementsByClassName("choices")
for (var i = 0; i < target.length; i++) {
target[i].querySelector(".pe-card__content").style.width = "100%"
}
},
view: function() {
return [
m("div", {
style: {
flexGrow: "1"
}
}), m(Card, {
className: "choices",
style: {
width: "100%",
flexGrow: "1"
},
content: [
{
text: {
content: [
m(".flex", m(TextField, {
label: "Teks",
required: true,
floatingLabel: true,
tight: true,
value: newChoice.data.text,
events: {
oninput: m.withAttr("value", function(value) {
newChoice.data.text = value
})
}
}), m("div", m.trust("&nbsp;")), m(Checkbox, {
style: {
marginTop: "2.5em",
flexBasis: "25%"
},
label: "Dapat diisi",
checked: newChoice.data.fillable,
onChange: function(state) {
newChoice.data.fillable = state.checked
}
})),
m(".flex", [
m(TextField, {
label: "Deskripsi",
floatingLabel: true,
tight: true,
value: newChoice.data.description,
events: {
oninput: m.withAttr("value", function(value) {
newChoice.data.description = value
})
}
})
]),
m("div", {
style: {
textAlign: "right"
}
}, [
m(RaisedButton, {
label: [
m("i.fa.fa-plus.fa-fw"),
m.trust("&nbsp;"),
"Tambah"
],
tone: "dark",
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "#009933"
},
events: {
onclick: function() {
Choices.data.push(newChoice.data)
m.mount(
document.getElementById("choice-new"),
{
view: function() {
return m(newChoice)
}
}
)
}
}
}),
m(RaisedButton, {
label: [
m("i.fa.fa-times.fa-fw"),
m.trust("&nbsp;"),
"Batal"
],
tone: "dark",
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "#ff0000"
},
events: {
onclick: function() {
m.mount(
document.getElementById("choice-new"),
{
view: function() {
return m(plusButton)
}
}
)
}
}
})
])
]
}
}
]
}), m("div", {
style: {
flexGrow: "1"
}
})
]
}
}
var qsCard = {
form: powerform({
text: function(v) {
if (!v || v == "" || _.isNil(v) || _.isEmpty(v)) {
return "Kolom ini harus diisi"
}
},
length: function(v) {
if (!_.isNil(v) || !_.isEmpty(v)) {
if (/^\d+$/.test(v) == false) {
return "Kolom ini diisi dengan angka"
}
}
},
type: function(v) {
if (!v || v == "" || _.isNil(v) || _.isEmpty(v)) {
return "Kolom ini harus diisi"
}
},
// fill: function(v) {},
// choices: function(v) {},
}),
oncreate: function() {
qsCard.form.text(Question.current.text)
qsCard.form.length(Question.current.expectedLength)
qsCard.form.type(Question.current.questionType)
},
view: function() {
return m("form", {
onsubmit: function(e) {
e.preventDefault()
console.log(qsCard.form.isValid(), qsCard.form.error());
},
style: {
flexGrow: "1",
display: "flex"
}
}, m(Card, {
style: {
flexGrow: "1",
marginBottom: "14vh",
// marginTop: "11vh"
},
content: [
{
text: {
className: "edit-body",
content: [
m(TextField, {
label: "Judul",
floatingLabel: true,
tight: true,
value: Question.current.text,
events: {
oninput: m.withAttr("value", function(v) {
Question.current.text = v
qsCard.form.text(v)
})
},
validate: function() {
return {
valid: qsCard.form.text.isValid(),
error: qsCard.form.text.error()
}
}
}),
m(TextField, {
label: "Deskripsi",
floatingLabel: true,
tight: true,
value: Question.current.description,
events: {
oninput: m.withAttr("value", function(v) {
Question.current.description = v
})
},
}),
m(TextField, {
label: "Minimal Karakter",
floatingLabel: true,
tight: true,
// type: "number",
value: Question.current.expectedLength,
events: {
oninput: m.withAttr("value", function(v) {
Question.current.expectedLength = v
qsCard.form.length(v)
})
},
validate: function(v) {
if (_.isNil(v) || _.isEmpty(v)) {
qsCard.form.length.isValid(true)
} else {
return {
valid: qsCard.form.length.isValid(),
error: qsCard.form.length.error()
}
}
}
}),
m("div", {
style: {
color: "rgba(0, 0, 0, .4)",
fontSize: "small",
fontWeight: "400",
lineHeight: "24px",
marginBottom: ".5em"
}
}, "Tipe *"),
m(RadioGroup, {
name: "type",
buttons: [
{
label: "Teks",
value: "text",
defaultChecked: Question.current.questionType == "text"
},
{
label: "Pilihan",
value: "choice",
defaultChecked: Question.current.questionType == "choice"
|| Question.current.questionType == "multichoice"
},
{
label: "Angka",
value: "numeric",
defaultChecked: Question.current.questionType == "numeric"
},
{
label: "Benar/Salah",
value: "bool",
defaultChecked: Question.current.questionType == "bool"
}
],
onChange: function(state) {
Question.current.questionType = state.value
qsCard.form.type(state.value)
}
}),
Question.current.questionType == "choice"
|| Question.current.questionType == "multichoice" ?
[
m(Choices, {data: Question.current.choices})
]
: null
]
}
},
{
actions: {
bordered: true,
content: [
m(RaisedButton, {
element: "button",
label: [
m("i.fa.fa-floppy-o.fa-fw"),
m.trust("&nbsp;"),
"Simpan"
],
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "#00cc00"
},
tone: "dark"
}),
m(".flex"),
m(RaisedButton, {
label: [
m("i.fa.fa-times.fa-fw"),
m.trust("&nbsp;"),
"Hapus"
],
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "#ff0000"
},
tone: "dark"
})
]
}
}
]
}))
}
}
export const editQuestion = {
oninit: function(vnode) {
Question.current = {id: vnode.attrs.id}
Question.fetchCurrent()
},
view: function() {
return [
m(nav, {
title: "Ubah - " + Question.current.text,
back: "/user/questions/" + Question.current.id
}),
m(".flex", m(qsCard))
]
}
}

View File

@@ -0,0 +1,159 @@
import m from "mithril"
import moment from "moment"
import powerform from "powerform"
import { Card, RaisedButton, TextField } from "polythene-mithril"
import DatePicker from "../custom/mithril-datepicker"
import {} from "../../css/custom/mithril-datepicker.css"
import { nav } from "./nav"
import Questionnaire from "../models/Questionnaire"
var qCard = {
form: powerform({
title: function(v) {
if (!v || v == "" || _.isEmpty(v) || _.isNil(v)) {
return "Kolom ini harus diisi"
}
},
release: function(v) {
if (!v || v == "" || _.isEmpty(v) || _.isNil(v)) {
return "Kolom ini harus diisi"
}
}
}),
oninit: function() {
qCard.form.title(Questionnaire.current.title)
},
oncreate: function() {
Questionnaire.current.releasedAt = moment().format("YYYY-MM-DD HH:mm:ss")
qCard.form.release(Questionnaire.current.releasedAt)
},
view: function() {
return m("form", {
style: {flexGrow: "1", display: "flex"},
onsubmit: function(e) {
e.preventDefault()
if (qCard.form.isValid()) {
m.route.set("/user/questionnaires/" + Questionnaire.current.id)
}
}
}, m(Card, {
style: {
flexGrow: "1"
},
content: [
{
text: {
content: [
m(TextField, {
label: "Judul",
floatingLabel: true,
tight: true,
value: Questionnaire.current.title,
events: {
oninput: m.withAttr("value", function(v) {
Questionnaire.current.title = v
qCard.form.title(v)
})
},
validate: function() {
return {
valid: qCard.form.title.isValid(),
error: qCard.form.title.error()
}
}
}),
m(TextField, {
label: "Deskripsi",
required: true,
floatingLabel: true,
tight: true,
value: Questionnaire.current.description,
events: {
oninput: m.withAttr("value", function(v) {
Questionnaire.current.description = v
})
}
}),
m("div", {
style: {
color: "rgba(0, 0, 0, .4)",
fontSize: "small",
fontWeight: "400",
lineHeight: "24px",
marginBottom: ".5em"
}
}, "Tanggal Rilis *"),
m(DatePicker, {
date: moment(Questionnaire.current.releasedAt),
locale: "id-id",
onchange: function(v) {
Questionnaire.current.releasedAt =
moment(v).format("YYYY-MM-DD HH:mm:ss")
qCard.form.release(Questionnaire.current.releasedAt)
}
})
]
}
},
{
actions: {
bordered: true,
content: [
m(RaisedButton, {
element: "button",
label: [
m("i.fa.fa-floppy-o.fa-fw"),
m.trust("&nbsp;"),
"Simpan"
],
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "rgb(255, 153, 0)"
},
tone: "dark"
}),
m(".flex"),
m(RaisedButton, {
label: [
m("i.fa.fa-times.fa-fw"),
m.trust("&nbsp;"),
"Hapus"
],
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "rgb(255, 0, 0)"
},
tone: "dark"
})
]
}
}
]
}))
}
}
export const editQuestionnaire = {
oninit: function() {
Questionnaire.fetchCurrent()
},
view: function() {
return [
m(nav, {
title: "Ubah - " + Questionnaire.current.title,
back: "/user/questionnaires/" + Questionnaire.current.id
}),
m(".flex", m(qCard))
]
}
}

644
assets/js/components/editSection.js vendored Normal file
View File

@@ -0,0 +1,644 @@
import m from "mithril"
import moment from "moment"
import _ from "lodash"
import powerform from "powerform"
import { Card, Button, RaisedButton, TextField, Dialog, Snackbar } from "polythene-mithril"
import DatePicker from "../custom/mithril-datepicker"
import {} from "../../css/custom/mithril-datepicker.css"
import { nav } from "./nav"
import Section from "../models/Section"
var Question = {
view: function(vnode) {
var data = vnode.attrs.data
return _.isEmpty(data) ?
m(".flex#question-new", m(newQuestion))
: [
m("div", data.map(function(question) {
return m(".flex.drag-wrapper", m(viewQuestion, {data: question}))
}), m(".flex", m(plusButton)))
]
}
}
var plusButton = {
view: function() {
return m(".flex#question-new", m(Button, {
className: "flex",
label: [
m("i.fa.fa-plus.fa-fw"),
m.trust("&nbsp;"),
"Tambah"
],
style: {
padding: ".8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
transition: ".2s all ease"
},
events: {
onmouseover: function() {
this.childNodes[0].style.backgroundColor = "rgba(255, 255, 255, .8)"
},
onmouseout: function() {
this.childNodes[0].style.backgroundColor = "#fff"
},
onclick: function() {
m.mount(document.getElementById("question-new"), {
view: function() {
return m(newQuestion)
}
})
}
}
}))
}
}
var editQuestion = {
view: function(vnode) {
var data = vnode.attrs.data
return [
m(Card, {
style: {
flexGrow: "1"
},
content: [
{
text: {
content: [
m(TextField, {
label: "Teks",
required: true,
floatingLabel: true,
tight: true,
value: data.text,
events: {
oninput: m.withAttr("value", function(value) {
data.text = value
})
}
}),
m(TextField, {
label: "Deskripsi",
floatingLabel: true,
tight: true,
value: data.description,
events: {
oninput: m.withAttr("value", function(value) {
data.description = value
})
}
}),
m("div", {
style: {
textAlign: "right"
}
}, [
m(RaisedButton, {
label: [
m("i.fa.fa-check.fa-fw"),
m.trust("&nbsp;"),
"Simpan"
],
tone: "dark",
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "#009933"
},
events: {
onclick: function() {
m.mount(
vnode.attrs.parent,
{
view: function() {
return m(viewQuestion, {data: data})
}
}
)
}
}
}),
m(RaisedButton, {
label: [
m("i.fa.fa-check.fa-fw"),
m.trust("&nbsp;"),
"Batal"
],
tone: "dark",
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "#ff0000"
},
events: {
onclick: function() {
m.mount(
vnode.attrs.parent,
{
view: function() {
return m(viewQuestion, {data: data})
}
}
)
}
}
})
])
]
}
}
]
})
]
}
}
var newQuestion = {
data: {},
form: powerform({
req: function(v) {
if (!v || v == "" || _.isEmpty(v) || _.isNil(v)) {
return "Kolom ini harus diisi"
}
}
}),
oninit: function() {
newQuestion.data = {}
},
oncreate: function() {
document.getElementById("question-text")
.querySelector("input").focus()
},
view: function() {
return [
m(Card, {
style: {
flexGrow: "1"
},
content: [
{
text: {
content: [
m("form", {
onsubmit: function(e) {
e.preventDefault()
if (newQuestion.form.isValid()) {
var target = document.getElementById("question-new")
.parentNode
var targetParent = Array.prototype
.slice.call(target.parentNode.childNodes)
var index = targetParent.indexOf(target) + 1
newQuestion.data.number = index
Section.current.questions
.push(newQuestion.data)
m.mount(
document.getElementById("question-new"),
{
view: function() {
return m(newQuestion)
}
}
)
}
}
}, [
m(TextField, {
id: "question-text",
label: "Teks",
floatingLabel: true,
tight: true,
value: newQuestion.data.text,
events: {
oninput: m.withAttr("value", function(value) {
newQuestion.data.text = value
newQuestion.form.req(value)
})
},
validate: function() {
return {
valid: newQuestion.form.req.isValid(),
error: newQuestion.form.req.error()
}
}
}),
m(TextField, {
id: "question-description",
label: "Deskripsi",
floatingLabel: true,
tight: true,
value: newQuestion.data.description,
events: {
oninput: m.withAttr("value", function(value) {
newQuestion.data.description = value
})
}
}),
m("div", {
style: {
textAlign: "right"
}
}, [
m(RaisedButton, {
element: "button",
type: "submit",
label: [
m("i.fa.fa-check.fa-fw"),
m.trust("&nbsp;"),
"Tambah"
],
tone: "dark",
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "#009933"
}
}),
m(RaisedButton, {
label: [
m("i.fa.fa-check.fa-fw"),
m.trust("&nbsp;"),
"Batal"
],
tone: "dark",
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "#ff0000"
},
events: {
onclick: function() {
newQuestion.data = {}
m.mount(
document.getElementById("question-new"),
{
view: function() {
return m(plusButton)
}
}
)
}
}
})
])
])
]
}
}
]
})
]
}
}
var trashSVG = "<svg width=\"1792\" height=\"1792\" viewBox=\"0 0 1792 1792\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\"><path d=\"M704 736v576q0 14-9 23t-23 9h-64q-14 0-23-9t-9-23v-576q0-14 9-23t23-9h64q14 0 23 9t9 23zm256 0v576q0 14-9 23t-23 9h-64q-14 0-23-9t-9-23v-576q0-14 9-23t23-9h64q14 0 23 9t9 23zm256 0v576q0 14-9 23t-23 9h-64q-14 0-23-9t-9-23v-576q0-14 9-23t23-9h64q14 0 23 9t9 23zm128 724v-948h-896v948q0 22 7 40.5t14.5 27 10.5 8.5h832q3 0 10.5-8.5t14.5-27 7-40.5zm-672-1076h448l-48-117q-7-9-17-11h-317q-10 2-17 11zm928 32v64q0 14-9 23t-23 9h-96v948q0 83-47 143.5t-113 60.5h-832q-66 0-113-58.5t-47-141.5v-952h-96q-14 0-23-9t-9-23v-64q0-14 9-23t23-9h309l70-167q15-37 54-63t79-26h320q40 0 79 26t54 63l70 167h309q14 0 23 9t9 23z\"/></svg>"
var viewQuestion = {
oncreate: function() {
var drags = document.getElementsByClassName("draggable")
for (var i = 0; i < drags.length; i++) {
drags[i].draggable = true
drags[i].ondragstart = sCard.onDrag
drags[i].parentNode.ondrop = sCard.onDrop
drags[i].parentNode.ondragover = sCard.onDragOver
drags[i].parentNode.ondragleave = sCard.onDragLeave
}
},
view: function(vnode) {
var data = vnode.attrs.data
return [
m(Card, {
style: {
flexGrow: "1"
},
id: "question-" + data.number,
className: "draggable",
content: [
{
text: {
content: [
m("i.fa.fa-times.fa-fw#remove" + data.id, {
style: {
position: "absolute",
right: "0",
cursor: "pointer"
}
}),
m("h5", data.text),
m("div", data.description)
]
}
}
],
events: {
onclick: function(e) {
var parent = this.parentNode
if (e.target != document.querySelector("#remove" + data.id)) {
return m.mount(parent, {
view: function() {
return m(editQuestion, {data: data, parent: parent})
}
})
} else {
Dialog.show({
body: [
m(".pe-dialog-pane__title", "Hapus " + data.text),
m("div", "Pertanyaan ini akan dihapus setelah klik pada tombol 'Simpan'.")
],
footerButtons: [
m(Button, {
label: "Konfirmasi",
events: {
onclick: function() {
_.remove(
Section.current.questions,
function(o) {
return o.id == data.id
}
)
// var target = document.getElementById("question-" + data.number)
// target.parentNode.removeChild(target)
for (var i = 0; i < Section.current.questions.length; i++) {
Section.current.questions[i].number = i + 1
}
Dialog.hide()
}
}
}),
m(Button, {
label: "Batal",
events: {
onclick: Dialog.hide
}
})
],
backdrop: true,
didHide: function() {
if (document.body.querySelector(".flex .pe-dialog__holder") != null) {
document.body.querySelector(".flex").removeChild(
document.body.querySelector(".flex .pe-dialog__holder")
)
}
document.body.className = ""
}
})
}
},
onmousedown: function() {
if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|BB|PlayBook|IEMobile|Windows Phone|Kindle|Silk|Opera Mini/i.test(navigator.userAgent) == false) {
Snackbar.show({
id: "protip",
title: [
m("span", {
style: {color: "rgb(255, 153, 0)"}
}, "Tips", m("i.fa.fa-lightbulb-o.fa-fw[aria-hidden=true]")),
": Tahan dan geser item untuk memindahkan urutan"
],
action: m(Button, {
id: "protip-button",
label: m("i.fa.fa-times[aria-hidden=true]"),
events: {
onclick: function() {
Snackbar.hide()
},
oncreate: function() {
document.body
.querySelector(".flex #protip #protip-button")
.style.minWidth = "0"
}
}
}),
timeout: 5,
didHide: function() {
if (document.body.querySelector(".flex #protip") != null) {
document.body.querySelector(".flex").removeChild(
document.body.querySelector(".flex #protip").parentNode
)
}
document.body.className = ""
}
})
}
}
}
})
]
}
}
var sCard = {
onDrag: function(e) {
e.dataTransfer.setData("element", e.target.id)
},
onDrop: function(e) {
e.preventDefault()
var data = document.getElementById(e.dataTransfer.getData("element"))
var dataParent = data.parentNode
var target = this
var newIndex = Array.prototype.slice.call(target.parentNode.childNodes)
.indexOf(this)
var oldIndex = Array.prototype.slice.call(dataParent.parentNode.childNodes)
.indexOf(dataParent)
Section.current.questions[oldIndex].number = newIndex + 1
Section.current.questions[newIndex].number = oldIndex + 1
Section.current.questions = _.sortBy(Section.current.questions, function(o) {
return o.number
})
m.redraw()
target.style.backgroundColor = "transparent"
},
onDragOver: function(e) {
e.preventDefault()
this.style.backgroundColor = "rgba(0, 0, 0, .2)"
},
onDragLeave: function(e) {
e.preventDefault()
this.style.backgroundColor = "transparent"
},
form: powerform({
req: function(v) {
if (!v || v == "" || _.isEmpty(v) || _.isNil(v)) {
return "Kolom ini harus diisi"
}
}
}),
oninit: function() {
sCard.form.req(Section.current.title)
},
view: function() {
return m("form", {
onsubmit: function(e) {
e.preventDefault()
if (sCard.form.isValid()) {
m.route.set("/user/sections/" + Section.current.id)
}
},
style: {
flexGrow: "1",
display: "flex"
}
}, m(Card, {
style: {flexGrow: "1"},
content: [
{
text: {
content: [
m(TextField, {
label: "Judul",
floatingLabel: true,
tight: true,
value: Section.current.title,
events: {
oninput: m.withAttr("value", function(v) {
Section.current.title = v
sCard.form.req(v)
})
},
validate: function() {
return {
valid: sCard.form.req.isValid(),
error: sCard.form.req.error()
}
}
}),
m(TextField, {
label: "Deskripsi",
floatingLabel: true,
tight: true,
value: Section.current.description,
events: {
oninput: m.withAttr("value", function(v) {
Section.current.description = v
})
}
}),
m(".flex", {
style: {
fontSize: "larger"
}
}, "Pertanyaan"),
m(Question, {data: Section.current.questions})
]
}
},
{
actions: {
bordered: true,
content: [
m(RaisedButton, {
element: "button",
label: [
m("i.fa.fa-floppy-o.fa-fw"),
m.trust("&nbsp;"),
"Simpan"
],
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "#00cc00"
},
tone: "dark",
}),
m(".flex"),
m(RaisedButton, {
label: [
m("i.fa.fa-times.fa-fw"),
m.trust("&nbsp;"),
"Hapus"
],
style: {
padding: ".6em .8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
backgroundColor: "#ff0000"
},
tone: "dark",
events: {
onclick: function() {
Dialog.show({
body: [
m(".pe-dialog-pane__title", "Hapus seksi"),
m("div", "Apakah Anda yakin akan menghapus seksi ini?")
],
footerButtons: [
m(Button, {
label: "Ya",
events: {
onclick: function() {
m.route.set("/user/questionnaires/" + Section.current.questionnaire.id)
}
}
}),
m(Button, {
label: "Tidak",
events: {
onclick: Dialog.hide
}
})
],
backdrop: true,
didHide: function() {
if (document.body.querySelector(".flex .pe-dialog__holder") != null) {
document.body.querySelector(".flex").removeChild(
document.body.querySelector(".flex .pe-dialog__holder")
)
}
document.body.className = ""
}
})
}
}
})
]
}
}
]
}))
}
}
export const editSection = {
oninit: function() {
Section.fetchCurrent()
Section.current.questions = _.sortBy(Section.current.questions, function(o) {
return o.number
})
},
view: function() {
return [
m(nav, {
title: "Seksi - " + Section.current.title,
back: "/user/sections/" + Section.current.id
}),
m(".flex", m(sCard), m(Dialog), m(Snackbar)),
]
}
}

231
assets/js/components/header.js vendored Normal file
View File

@@ -0,0 +1,231 @@
import m from "mithril"
import { Toolbar, ToolbarTitle, TextField, Button } from "polythene-mithril"
// import { User } from "../models/User"
var email = {
value: "",
setValue: function(v) { email.value = v },
getValue: function() { return email.value }
}
const workflow = [
{
number: 1,
text: "Daftarkan email pada kolom email di atas.",
subText: "Jika sudah pernah mendaftar, lanjut ke langkah 4"
},
{
number: 2,
text: "Isi formulir data diri."
},
{
number: 3,
text: "Server mengirim email berupa kode login."
},
{
number: 4,
text: "Pilih kuesioner yang akan diisi."
},
{
number: 5,
text: "Masukkan kode login Anda (langkah 3)."
},
{
number: 6,
text: "Silahkan isi kuesioner!"
}
]
export const header = {
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("i.fa.fa-check-square.fa-fw[aria-hidden=true]"),
m.trust("&nbsp;"),
m("span", "Questionnaire"),
m.trust("&nbsp;"),
m("i.fa.fa-window-close.fa-fw[aria-hidden=true]")
]),
m("p", "Web-based kuesioner untuk Yayasan Widya Anindya"),
m("div", { style: { margin: "5em 0" } }),
m("form", {
onsubmit: function(e) {
e.preventDefault()
/* upload data email */
/* alias */
// if (email.value == "admin@questionnaire.dev") {
// m.route.set("/questionnaires")
// } else if (email.value == "") {
// document.getElementById("header-email")
// .querySelector("input").focus()
// } else {
// m.route.set("/auth/register/?invoker=" + email.value)
// }
m.route.set("/auth/register")
}
}, m(TextField, {
label: "E-mail",
id: "header-email",
name: "email",
value: User.current.email,
style: {
padding: ".3em 1em .8em",
borderRadius: "2px"
},
pattern: "[a-z\-\.0-9]+@[a-z\-\.]+[a-z]+",
validateOnInput: true,
tone: "dark",
onChange: function(state) {
User.current.email = state.value
},
events: {
oncreate: function() {
var target = document.getElementById("header-email")
var selector = target.querySelector("input")
selector.onfocus = function() {
target.style
.backgroundColor = "rgba(0, 0, 0, .5)"
}
selector.autocomplete = "off"
target.removeChild(
target.querySelector(
".pe-textfield__error-placeholder"
)
)
}
}
}),
m(Button, {
element: "button",
type: "submit",
label: [
m("i.fa.fa-check-square-o.fa-fw[aria-hidden=true]"),
m.trust("&nbsp;"),
"Mulai"
],
style: {
backgroundColor: "#fff",
padding: ".8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
}
}))
])),
m(".header-content", m("article", {
style: {
backgroundColor: "#fff",
}
}, [
m("h2.article-title", [
m("i.fa.fa-rocket[aria-hidden=true]", {
style: {
color: "rgb(255, 153, 0)"
}
}),
m("div", {
style: {
marginTop: ".3em"
}
}, "Workflow")
]),
workflow.map(function(v) {
return m(".workflow-items-wrapper.flex", v.number == workflow.length ? {
style: {
marginBottom: "0"
}
} : null, [
m(".workflow-items", m("div", v.number)),
m(".workflow-items-description", m("p", [
v.text,
!_.isNil(v.subText) ?
[
m("br"),
m("i", "(" + v.subText + ")")
]
: null
]))
])
}),
m(".article-break"),
m("h2.article-title", {
style: {
marginBottom: "0"
}
}, [
m("i.fa.fa-space-shuttle.fa-rotate-270[aria-hidden=true]", {
style: {
color: "rgb(255, 153, 0)",
cursor: "pointer",
transition: "all .5s ease",
webkitTransition: "all .5s ease",
mozTransition: "all .5s ease",
oTransition: "all .5s ease"
},
onclick: function() {
var scrollValue = 1
var scrolling = setInterval(function() {
window.scrollTo(0, window.scrollY - scrollValue)
if (window.scrollY <= 100) {
scrollValue--
} else if (window.scrollY <= 0) {
window.clearInterval(scrolling)
document.getElementById("header-email")
.querySelector("input").focus()
} else {
scrollValue++
}
}, 10)
},
onmouseover: function() {
this.style.transform = "translateY(-0.2em) rotate(270deg)"
var target = document.getElementById("ready-text")
target
.style.color = "rgb(255, 153, 0)"
target
.innerHTML = target.innerHTML.replace("?", "!")
},
onmouseout: function() {
this.style.transform = "translateY(0) rotate(270deg)"
var target = document.getElementById("ready-text")
target
.style.color = "rgb(0, 0, 0)"
target
.innerHTML = target.innerHTML.replace("!", "?")
}
}),
m("#ready-text", {
style: {
marginTop: ".3em"
}
}, "Siap?")
]),
m(".article-break")
]))
]
}
}

66
assets/js/components/hello.js vendored Normal file
View File

@@ -0,0 +1,66 @@
// import m from "mithril"
// import { Button } from "polythene-mithril"
// import { Dialog } from "polythene-mithril"
// import { addTypography } from "polythene-css"
//
// addTypography()
//
// export const hello = {
// view: function() {
// return [
// m(Button, {
// label: 'Show dialog',
// events: {
// onclick: function() {
// return Dialog.show({
// title: 'Hello',
// body: 'Click outside to close, or press ESCAPE',
// backdrop: true
// })
// }
// }
// }),
// m(Dialog)
// ]
// }
// }
import m from "mithril"
import powerform from "powerform"
import { required, equalsTo } from "validatex"
const form = powerform({
username: required(true),
password: required(true),
confirmPassword: [required(true), equalsTo("password")]
})
const signup = {
view: function() {
return [
m("input", {
placeholder: "Username",
onkeyup: m.withAttr("value", form.username),
onchange: form.username.isValid
}),
m("p.error", form.username.error()),
m("input", {
placeholder: "Password",
onkeypress: m.withAttr("value", form.password),
onchange: form.password.isValid
}),
m("p.error", form.password.error()),
m("input", {
placeholder: "Confirm Password",
onkeypress: m.withAttr("value", form.confirmPassword),
onchange: form.confirmPassword.isValid
}),
m("p.error", form.confirmPassword.error()),
m("button", {
onclick: form.isValid()
}, "Submit")
]
}
}
export default signup

54
assets/js/components/nav.js vendored Normal file
View File

@@ -0,0 +1,54 @@
import m from "mithril"
import { Toolbar, ToolbarTitle } from "polythene-mithril"
import { backButton, logoutButton } from "./buttons"
export const nav = {
view: function(vnode) {
return m(Toolbar, {
style: {
backgroundColor: "rgb(255, 153, 0)",
// position: "fixed",
width: "100%",
// zIndex: "12"
},
tone: "dark",
compact: true
}, [
vnode.attrs.back != false ?
m({
view: function() {
return m("div.nav-button", {
style: {
marginLeft: "1em",
cursor: "pointer"
},
onclick: function() {
/* Request ke question model */
// qsModel.fetch(qsId.qsuestionnaire.url)
/* Route */
m.route.set(vnode.attrs.back)
}
}, m(backButton))
}
})
: null,
m(ToolbarTitle, {
id: "nav-title",
style: {
margin: "0 auto"
},
text: m("span#nav-title__text", vnode.attrs.title),
center: true
}),
m("div.nav-button", {
style: {
marginRight: "1em",
cursor: "pointer"
},
onclick: function() {
m.route.set("")
}
}, m(logoutButton))
])
}
}

176
assets/js/components/question.js vendored Normal file
View File

@@ -0,0 +1,176 @@
import m from "mithril"
import { RaisedButton, Card, Button } from "polythene-mithril"
import { nav } from "./nav"
import * as QuestionType from "./questionType"
import { editButton } from "./buttons"
let qsList = require("../../json/section/id/questions/example")
let qsId = require("../../json/question/id/example70203")
var executeFunctionByName = function(functionName, context) {
var namespaces = functionName.split(".");
var func = namespaces.pop();
for(var i = 0; i < namespaces.length; i++) {
context = context[namespaces[i]];
}
return context[func];
}
var pagination = {
oncreate: function() {
for (var i = 0; i < document.getElementsByClassName("flex-single").length; i++) {
document.getElementsByClassName("flex-single")[i].style.flexGrow = 1
}
},
view: function() {
return m(".flex", {
style: {
backgroundColor: "#fff",
position: "fixed",
bottom: "0",
width: "100%",
padding: "1em",
zIndex: "21"
}
}, [
m(".flex-single"),
m(RaisedButton, {
className: "flex-single",
label: m("i.fa.fa-arrow-left.fa-fw", {
style: {
margin: "1em 0",
}
}),
events: {
onclick: function() {
var prev = _.find(qsList.data, function(o) { return o.id == parseInt(sId.data.id) - 1 })
if (prev != undefined) {
/* Request pake url yang tersedia */
// qModel.fetch(prev.url)
m.route.set("/sections/" + prev.id)
}
}
}
}),
m(".flex-single"),
m(RaisedButton, {
className: "flex-single",
label: m("i.fa.fa-arrow-right.fa-fw", {
style: {
margin: "1em 0",
}
}),
events: {
onclick: function() {
var next = _.find(qsList.data, function(o) { return o.id == parseInt(sId.data.id) + 1 })
if (next != undefined) {
/* Request pake url yang tersedia */
// sModel.fetch(next.url)
m.route.set("/sections/" + next.id)
}
}
}
}),
m(".flex-single")
])
}
}
var qsCard = {
view: function() {
return m(".flex", m(Card, {
style: {
flexGrow: "1",
marginBottom: "14vh",
// marginTop: "11vh"
},
content: [
{
primary: {
title: [
m(editButton, { redirectURL: "/questions/" + qsId.data.id + "/edit" }),
m("#title", qsId.data.text)
],
subtitle: qsId.data.description
}
},
{
text: {
content: [
m("div", {
style: {
marginBottom: "1em"
}
}, [
m("div.info", {
style: {
color: "#999"
}
}, "Nomor: " + qsId.data.number),
m("div.info", {
style: {
color: "#999"
}
}, "Tipe: " + qsId.data.questionType),
m("div.info", {
style: {
color: "#999"
}
}, "Dibuat: " + qsId.data.createdAt),
m("div.info", {
style: {
color: "#999"
}
}, "Pembuat: " + qsId.data.creator.name),
m("div.info", {
style: {
color: "#999"
}
}, "Diubah: " + qsId.data.updatedAt)
]),
m("p", {
style: {
fontSize: "large"
}
}, "Tampilan"),
m(".flex", {
style: {
flexFlow: "row wrap"
}
}, m(Card, {
style: {
flexGrow: "1",
flexBasis: "100%"
},
content: [
{
text: {
content: [
m(executeFunctionByName(qsId.data.questionType, QuestionType), {
data: qsId.data
})
]
}
}
]
})
)
]
}
}
]
}))
}
}
export const question = {
view: function() {
return [
m(nav, {
title: "Pertanyaan #" + qsId.data.id,
back: "/sections/" + qsId.data.sectionsUrl
}),
m(qsCard),
m(pagination)
]
}
}

220
assets/js/components/questionType.js vendored Normal file
View File

@@ -0,0 +1,220 @@
import m from "mithril"
import _ from "lodash"
import { TextField, RadioGroup, Checkbox } from "polythene-mithril"
export const text = {
view: function(vnode) {
var data = vnode.attrs.data
return m(TextField, {
id: data.elId || "",
label: data.text,
required: true,
floatingLabel: data.floatingLabel || true,
tight: true,
help: data.description || null
})
}
}
export const numeric = {
view: function(vnode) {
var data = vnode.attrs.data
return m(TextField, {
label: data.text,
required: true,
floatingLabel: _.isNil(data.floatingLabel) ? true : data.floatingLabel,
tight: true,
help: data.description || null,
validate: function(value) {
if (isNaN(value)) {
return {
valid: false,
error: "Gunakan angka"
}
} else {
return { valid: true }
}
},
validateOnInput: true
})
}
}
export const bool = {
view: function(vnode) {
var data = vnode.attrs.data
return [
m("div", {
style: {
color: "rgba(0, 0, 0, .4)",
fontSize: "16px",
fontWeight: "400",
lineHeight: "24px",
marginTop: ".5em"
}
}, data.text + " *"),
m("i", {
style: {
color: "rgba(0, 0, 0, .4)"
}
}, "(" + data.description + ")" || null),
m(RadioGroup, {
id: "bool",
className: "flex",
style: {
margin: ".5rem 0",
flexFlow: "row wrap"
},
buttons: [
{
id: "true",
label: "Benar",
value: true,
style: {
marginTop: ".5em",
marginBottom: ".5em",
marginRight: "0",
flexGrow: "1",
flexBasis: "100%"
}
},
{
id: "false",
label: "Salah",
value: false,
style: {
marginTop: ".5em",
marginBottom: ".5em",
marginRight: "0",
flexGrow: "1",
flexBasis: "100%"
}
}
]
})
]
}
}
export const multichoice = {
view: function(vnode) {
var data = vnode.attrs.data
return [
m("div", {
style: {
color: "rgba(0, 0, 0, .4)",
fontSize: "16px",
fontWeight: "400",
lineHeight: "24px",
marginTop: ".5em"
}
}, data.text + " *"),
m("i", {
style: {
color: "rgba(0, 0, 0, .4)"
}
}, "(" + data.description + ")" || null),
m(".flex", {
style: {
flexFlow: "row wrap"
}
}, data.choices.map(function(c) {
return m(Checkbox, {
id: "choice-" + c.id,
label: c.text,
value: c.id,
style: {
flexGrow: "1",
flexBasis: "100%",
marginTop: ".5em",
marginBottom: ".5em"
}
})
}))
]
}
}
export const choice = {
oncreate: function(vnode) {
var data = vnode.attrs.data
data.choices.map(function(c) {
if (c.fillable) {
var child = document.createElement("span")
child.style.marginLeft = ".5em"
child.style.marginTop = "1.4em"
var input = { view: function() {
return m(text, {
data: {
elId: "fillable-" + c.id,
text: "",
floatingLabel: false
}
})
}}
/* Get parent */
var parent = document.getElementById("choice-" + c.id).childNodes[0]
parent.appendChild(child)
m.mount(parent.querySelector("span"), input)
document.getElementById("fillable-" + c.id).querySelector("input").disabled = true
}
})
},
view: function(vnode) {
var data = vnode.attrs.data
return [
m("div", {
style: {
color: "rgba(0, 0, 0, .4)",
fontSize: "16px",
fontWeight: "400",
lineHeight: "24px",
marginTop: ".5em"
}
}, data.text + " *"),
m("i", {
style: {
color: "rgba(0, 0, 0, .4)"
}
}, "(" + data.description + ")" || null),
m(RadioGroup, {
id: "choices",
className: "flex",
style: {
margin: ".5rem 0",
flexFlow: "row wrap"
},
buttons: data.choices.map(function(c) {
return {
id: "choice-" + c.id,
value: c.id,
label: c.text,
style: {
marginTop: ".5em",
marginBottom: ".5em",
marginRight: "0",
flexGrow: "1",
flexBasis: "100%"
}
}
}),
onChange: function(state) {
var chosen = _.find(data.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").autofocus = true
} else {
data.choices.map(function(c) {
var target = document.getElementById("fillable-" + c.id)
if (!_.isNil(target)) {
target.querySelector("input").disabled = true
target.querySelector("input").value = ""
}
})
}
}
})
]
}
}

323
assets/js/components/questionnaire.js vendored Normal file
View File

@@ -0,0 +1,323 @@
import m from "mithril"
import _ from "lodash"
import { Card, Button, RaisedButton, Shadow, Menu, List, ListTile } from "polythene-mithril"
import { nav } from "./nav"
import { editButton, seeButton } from "./buttons"
import Questionnaire from "../models/Questionnaire"
const plusButton = {
view: function() {
return m(".flex#questionnaire-new", m(Button, {
className: "flex",
label: [
m("i.fa.fa-plus.fa-fw"),
m.trust("&nbsp;"),
"Tambah"
],
style: {
padding: ".8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
transition: ".2s all ease",
maxWidth: "95%",
margin: "0 auto"
},
events: {
onmouseover: function() {
this.childNodes[0].style.backgroundColor = "rgba(255, 255, 255, .8)"
},
onmouseout: function() {
this.childNodes[0].style.backgroundColor = "#fff"
},
onclick: function() {
}
}
}))
}
}
const filterMenu = {
oninit: function(vnode) {
var show = false
var sections = Questionnaire.current.sections.map(function(o) {
return {
title: o.status.charAt(0).toUpperCase() + o.status.slice(1),
value: o.status
}
})
var menus = []
menus.push({title: "All", value: "all"})
menus = menus.concat(sections.filter(function(value, index, self) {
return self.findIndex(function(v) {
return v.title === value.title && v.value === value.value
}) === index
}))
vnode.state = {
show,
menus
}
},
view: function(vnode) {
var state = vnode.state
var show = state.show
var menus = state.menus
return [
m(Shadow),
m(Menu, {
target: "#filter",
origin: "top-left",
show,
didHide: function() {state.show = false},
offset: 8,
size: 3,
hideDelay: .2,
content: m(List, {
tiles: menus.map(function(current) {
return {
title: current.title,
ink: true,
hoverable: true,
value: current.value
}
}),
keyboardControl: true,
onSelect: function({attrs}) {
if (attrs.value == "all") return Questionnaire.current.search = []
return Questionnaire.current.search = _.filter(Questionnaire.current.sections, function(o) {
return o.status == attrs.value
})
}
})
}),
m(RaisedButton, {
id: "filter",
label: [
m("i.fa.fa-filter.fa-fw[aria-hidden=true]"),
m.trust("&nbsp;"),
"Saring"
],
style: {
backgroundColor: "#fff",
padding: ".8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
},
events: {
onclick: function() { state.show = true }
}
})
]
}
}
const qCard = {
view: function() {
var sections =
_.isNil(Questionnaire.current.search)
|| _.isNull(Questionnaire.current.search)
|| _.isEmpty(Questionnaire.current.search) ?
Questionnaire.current.sections
: Questionnaire.current.search
return m(Card, {
style: {
flexGrow: "1",
marginBottom: "14vh",
// marginTop: "11vh"
},
content: [
{
primary: {
title: [
m(editButton, { redirectURL: "/user/questionnaires/" + Questionnaire.current.id + "/edit"}),
m("#title", Questionnaire.current.title)
],
subtitle: Questionnaire.current.description
}
},
{
text: {
content: [
m("div", {
style: {
marginBottom: "1em"
}
}, [
m("div.info", {
style: {
color: "#999"
}
}, "Dibuat: " + Questionnaire.current.createdAt),
m("div.info", {
style: {
color: "#999"
}
}, "Pembuat: " + Questionnaire.current.creator.name),
m("div.info", {
style: {
color: "#999"
}
}, "Dirilis: " + Questionnaire.current.releasedAt),
// m("div.info", {
// style: {
// color: "#999"
// }
// }, "Diperiksa: " + Questionnaire.current.reviewedAt),
// m("div.info", {
// style: {
// color: "#999"
// }
// }, "Pemeriksa: " + Questionnaire.current.reviewer.name),
m("div.info", {
style: {
color: "#999"
}
}, "Diubah: " + Questionnaire.current.updatedAt)
]),
m("p", {
style: {
fontSize: "large"
}
}, "Seksi"),
// m(filterMenu),
m("div", {
style: {margin: "0 1em"}
}, m("i.fa.fa-filter.fa-fw[aria-hidden=true]"), " Saring: ", [
{title: "Semua", icon: "circle-o", value: "all"},
{title: "Dirilis", icon:"upload", value: "released"},
{title: "Draft", icon:"file-text-o", value: "draft"},
{title: "Ditutup", icon:"times", value: "closed"}
].map(function(o) {
return m("a", {
style: {
color: "rgb(0, 0, 255)",
cursor: "pointer",
margin: "0 1em"
},
onclick: function() {
Questionnaire.current.search =
_.filter(
Questionnaire.current.sections,
function(i) {return i.status == o.value}
)
console.log(Questionnaire.current.search);
}
}, m("i.fa.fa-fw.fa-" + o.icon + "[aria-hidden=true]"), m.trust("&nbsp;"), o.title)
})),
m(".flex", {
style: {
flexFlow: "row wrap"
}
}, sections.map(function(s) {
return m(Card, {
style: {
flexGrow: "1",
flexBasis: "100%"
},
content: [
{
primary: {
title: m("a", {
style: {
cursor: "pointer"
},
onclick: function() {
m.route.set("/user/sections/" + s.id)
}
}, s.title + "[" + s.status + "]"),
subtitle: s.description
}
}
]
})
})),
m(plusButton)
]
}
}
]
})
}
}
const pagination = {
oncreate: function() {
for (var i = 0; i < document.getElementsByClassName("flex-single").length; i++) {
document.getElementsByClassName("flex-single")[i].style.flexGrow = 1
}
},
view: function() {
return m(".flex", {
style: {
backgroundColor: "#fff",
position: "fixed",
bottom: "0",
width: "100%",
padding: "1em"
}
}, [
m(".flex-single"),
m(RaisedButton, {
className: "flex-single",
label: m("i.fa.fa-arrow-left.fa-fw", {
style: {
margin: "1em 0",
}
}),
events: {
onclick: function() {
// var prev = _.find(qModel.list, function(o) { return o.id == parseInt(qModel.current.id) - 1 })
var prev = _.find(qJSON.data, function(o) { return o.id == parseInt(Questionnaire.current.id) - 1 })
if (prev != undefined) {
/* Request pake url yang tersedia */
// qModel.fetch(prev.url)
m.route.set("/questionnaires/" + prev.id)
}
}
}
}),
m(".flex-single"),
m(RaisedButton, {
className: "flex-single",
label: m("i.fa.fa-arrow-right.fa-fw", {
style: {
margin: "1em 0",
}
}),
events: {
onclick: function() {
// var next = _.find(qModel.list, function(o) { return o.id == parseInt(qModel.current.id) + 1 })
var next = _.find(qJSON.data, function(o) { return o.id == parseInt(Questionnaire.current.id) + 1 })
if (next != undefined) {
/* Request pake url yang tersedia */
// qModel.fetch(next.url)
m.route.set("/questionnaires/" + next.id)
}
}
}
}),
m(".flex-single")
])
}
}
export const questionnaire = {
oninit: function() {
Questionnaire.fetchCurrent()
},
view: function() {
return [
m(nav, {
title: "Kuesioner #" + Questionnaire.current.id,
back: "/user/questionnaires"
}),
m(".flex", m(qCard)),
m(pagination)
]
}
}

View File

@@ -0,0 +1,235 @@
import m from "mithril"
import { Card, Button, RaisedButton, Toolbar, ToolbarTitle, Search, Shadow, Menu, List, ListTile } from "polythene-mithril"
import { ButtonCSS, addTypography } from "polythene-css"
import { nav } from "./nav"
import Questionnaire from "../models/Questionnaire"
ButtonCSS.addStyle(".bordered-button", {
color_light_text: "#03a9f4",
color_light_border: "#03a9f4",
color_dark_text: "#03a9f4",
color_dark_border: "#03a9f4"
})
addTypography()
const head = {
view: function() {
return [
m(".header-nav.left", {
style: {
color: "#fff"
}
}, m("p", {
style: {
fontSize: "larger"
}
}, "Questionnaire")),
m(".header-nav", {
style: {
color: "#fff",
cursor: "pointer"
},
onclick: function() {
m.route.set("")
}
}, m("i.fa.fa-home.fa-lg")),
m(".header-img", {
style: {
backgroundImage: "url('img/head1.jpg')",
position: "fixed",
color: "#FFFFFF",
textAlign: "center",
width: "100%"
}
})
]
}
}
const plusButton = {
view: function() {
return m(".flex#questionnaire-new", m(Button, {
className: "flex",
label: [
m("i.fa.fa-plus.fa-fw"),
m.trust("&nbsp;"),
"Tambah"
],
style: {
padding: ".8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
transition: ".2s all ease",
maxWidth: "95%",
margin: "0 auto"
},
events: {
onmouseover: function() {
this.childNodes[0].style.backgroundColor = "rgba(255, 255, 255, .8)"
},
onmouseout: function() {
this.childNodes[0].style.backgroundColor = "#fff"
},
onclick: function() {
}
}
}))
}
}
const filterMenu = {
oninit: function(vnode) {
var show = false
vnode.state = {
show
}
},
view: function(vnode) {
var state = vnode.state
var show = state.show
return [
m(Shadow),
m(Menu, {
target: "#filter",
origin: "top-left",
show,
didHide: function() { state.show = false },
offset: 8,
size: 3,
hideDelay: .240,
content: m(List, {
tiles: Questionnaire.questionnaire.map(function(value) {
return {
title: value.status.charAt(0).toUpperCase() + value.status.slice(1),
value: value.status
}
}).map(function(current) {
return {
title: current.title,
ink: true,
hoverable: true,
value: current.value
}
}),
keyboardControl: true,
onSelect: function({attrs}) {
return Questionnaire.search = _.filter(Questionnaire.data, function(o) {
return o.status == attrs.value
})
}
})
}),
m(RaisedButton, {
id: "filter",
label: [
m("i.fa.fa-filter.fa-fw[aria-hidden=true]"),
m.trust("&nbsp;"),
"Saring"
],
style: {
backgroundColor: "#fff",
padding: ".8em",
fontSize: "14px",
lineHeight: "14px",
fontWeight: "500",
textTransform: "uppercase",
whiteSpace: "pre",
},
events: {
onclick: function() { state.show = true }
}
})
]
}
}
export const questionnaireList = {
oninit: function() {
Questionnaire.fetchList()
},
view: function() {
var questionnaire =
_.isNil(Questionnaire.search)
|| _.isNull(Questionnaire.search)
|| _.isEmpty(Questionnaire.search) ?
Questionnaire.list : Questionnaire.search
return [
m(nav, { title: "Questionnaires", back: false }),
m(Search, {
id: "search-questionnaire",
textfield: {
label: "Search",
autofocus: true,
onChange: function({value}) {
var regex = new RegExp(value, "gi")
Questionnaire.search = _.filter(Questionnaire.list, function(o) {
return o.title.match(regex)
})
}
},
before: m(Shadow)
}),
// m(filterMenu),
m("div", {
style: {margin: "1em 1em 0"}
}, m("i.fa.fa-filter.fa-fw[aria-hidden=true]"), " Saring: ", [
{title: "Semua", icon: "circle-o", value: "all"},
{title: "Dirilis", icon:"upload", value: "released"},
{title: "Draft", icon:"file-text-o", value: "draft"},
{title: "Ditutup", icon:"times", value: "closed"}
].map(function(o) {
return m("a", {
style: {
color: "rgb(0, 0, 255)",
cursor: "pointer",
margin: "0 1em"
},
onclick: function() {
Questionnaire.search =
_.filter(
Questionnaire.list,
function(i) {return i.status == o.value}
)
console.log(Questionnaire.search);
}
}, m("i.fa.fa-fw.fa-" + o.icon + "[aria-hidden=true]"), m.trust("&nbsp;"), o.title)
})),
m("div.flex", {
style: {
flexFlow: "row wrap",
justifyContent: "flex-start",
}
}, questionnaire.map(function(qs) {
return m(Card, {
className: "box",
style: {
flexGrow: "1"
},
content: [
{
primary: {
title: m("a", {
style: {
cursor: "pointer"
},
onclick: function() {
/* Request ke questionnaire model masuk ke current */
// qModel.fetch(qs.url)
/* Route */
m.route.set("/user/questionnaires/" + qs.id)
}
}, qs.title),
subtitle: qs.description.length > 56 ? qs.description.substr(0, 50) + " ..." : qs.desc
}
}
]
})
})),
m(plusButton)
]
}
}

174
assets/js/components/section.js vendored Normal file
View File

@@ -0,0 +1,174 @@
import m from "mithril"
import { RaisedButton, Card, Button } from "polythene-mithril"
import { nav } from "./nav"
import { editButton, seeButton } from "./buttons"
import Section from "../models/Section"
let sId = require("../../json/section/id/example")
let sList = require("../../json/questionnaire/id/sections/example")
var pagination = {
oncreate: function() {
for (var i = 0; i < document.getElementsByClassName("flex-single").length; i++) {
document.getElementsByClassName("flex-single")[i].style.flexGrow = 1
}
},
view: function() {
return m(".flex", {
style: {
backgroundColor: "#fff",
position: "fixed",
bottom: "0",
width: "100%",
padding: "1em"
}
}, [
m(".flex-single"),
m(RaisedButton, {
className: "flex-single",
label: m("i.fa.fa-arrow-left.fa-fw", {
style: {
margin: "1em 0",
}
}),
events: {
onclick: function() {
// var prev = _.find(sModel.list, function(o) { return o.id == parseInt(sModel.current.id) - 1 })
var prev = _.find(Section.list, function(o) { return o.id == parseInt(Section.current.id) - 1 })
if (prev != undefined) {
/* Request pake url yang tersedia */
// qModel.fetch(prev.url)
m.route.set("/sections/" + prev.id)
}
}
}
}),
m(".flex-single"),
m(RaisedButton, {
className: "flex-single",
label: m("i.fa.fa-arrow-right.fa-fw", {
style: {
margin: "1em 0",
}
}),
events: {
onclick: function() {
// var next = _.find(sModel.list, function(o) { return o.id == parseInt(sModel.current.id) + 1 })
var next = _.find(Section.list, function(o) { return o.id == parseInt(Section.current.id) + 1 })
if (next != undefined) {
/* Request pake url yang tersedia */
// sModel.fetch(next.url)
m.route.set("/sections/" + next.id)
}
}
}
}),
m(".flex-single")
])
}
}
var sCard = {
view: function() {
return m(".flex", m(Card, {
style: {
flexGrow: "1",
marginBottom: "14vh",
// marginTop: "11vh"
},
content: [
{
primary: {
title: [
m(editButton, { redirectURL: "/user/sections/" + Section.current.id + "/edit" }),
m("#title", Section.current.title)
],
subtitle: Section.current.description
}
},
{
text: {
content: [
m("div", {
style: {
marginBottom: "1em"
}
}, [
m("div.info", {
style: {
color: "#999"
}
}, "Dibuat: " + Section.current.createdAt),
m("div.info", {
style: {
color: "#999"
}
}, "Pembuat: " + Section.current.creator.name),
m("div.info", {
style: {
color: "#999"
}
}, "Diubah: " + Section.current.updatedAt)
]),
m("p", {
style: {
fontSize: "large"
}
}, "Pertanyaan"),
m(".flex", {
style: {
flexFlow: "row wrap"
}
}, _.sortBy(Section.current.questions, [function(o) {
return o.number
}]).map(function(sq) {
return m("#drag-wrapper-" + sq.id, {
style: {
flexGrow: "1",
flexBasis: "100%",
minHeight: "94px",
margin: ".5em 0"
}
}, m(Card, {
style: {width: "100%", margin: "0", padding: "0"},
id: sq.id,
className: "draggable",
content: [
{
primary: {
title: m("a", {
style: {
cursor: "pointer"
},
onclick: function() {
m.route.set("/user/questions/" + sq.id)
}
}, sq.text),
subtitle: sq.description
}
}
]
}))
}))
]
}
}
]
}))
}
}
export const section = {
oninit: function() {
if (_.isNil(Section.current) || _.isEmpty(Section.current)) Section.fetchCurrent()
},
view: function() {
return [
m(nav, {
title: "Seksi #" + Section.current.id,
back: "/user/questionnaires/" + Section.current.questionnaire.id
}),
m(sCard),
m(pagination)
]
}
}

393
assets/js/custom/mithril-datepicker.js vendored Normal file
View File

@@ -0,0 +1,393 @@
;(function () {
var m = (typeof global !== 'undefined')
? (global.m || require('mithril'))
: window.m
if (!m) throw ("mithril-datepicker can't find Mithril.js")
var days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
var months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
// var prevNextTitles = ['1 Mo', '1 Yr', '10 Yr']
var prevNextTitles = ['', '', '']
var weekStart = 0
var locale = 'en-us'
var formatOptions = null
/***************************************
*
* actions
*
***************************************/
function chooseDate(props, e) {
var box = e.target
var selectedDate = parseInt(box.textContent)
var dateObj = props.date
if (box.classList.contains('other-scope')) {
dateObj.setFullYear(dateObj.getFullYear(), dateObj.getMonth() + (selectedDate > 6 ? -1 : 1), selectedDate)
} else {
dateObj.setDate(selectedDate)
}
}
function dismissAndCommit(props, onchange) {
props.view = 0
props.active = false
if (onchange) onchange(props.date)
}
function prevNext(props, delta){
var newDate = new Date(props.date)
switch (props.view) {
case 0:
newDate.setMonth(newDate.getMonth() + delta)
break
case 1:
newDate.setFullYear(newDate.getFullYear() + delta)
break
default:
newDate.setFullYear(newDate.getFullYear() + (delta * 10))
}
props.date = pushToLastDay(props.date, newDate)
}
/***************************************
*
* utility
*
***************************************/
function adjustedProps(date, delta) {
var month = date.getMonth() + delta, year = date.getFullYear()
var over = month > 11, under = month < 0
return {
month: over ? 0 : under ? 11 : month,
year: over ? year + 1 : under ? year - 1 : year
}
}
function lastDateInMonth(date, delta) {
var obj = adjustedProps(date, delta)
if ([0, 2, 4, 6, 7, 9, 11].indexOf(obj.month) > -1) return 31 // array of 31-day props.months
if (obj.month === 1) { // February
if (!(obj.year % 400)) return 29
if (!(obj.year % 100)) return 28
return (obj.year % 4) ? 28 : 29
}
return 30
}
function pushToLastDay(oldDate, newDate) {
if (oldDate.getDate() !== newDate.getDate()) {
newDate.setMonth(newDate.getMonth() - 1, lastDateInMonth(newDate, -1))
}
return newDate
}
function stringsForLocale(locale) {
var date = new Date('jan 1 2017'), _months = [], _days = [] // 1/1/2017 was month:0 and weekday:0, so perfect
while (_days.length < 7) {
_days.push(date.toLocaleDateString(locale, { weekday: 'long' }))
date.setDate(date.getDate() + 1)
}
while (_months.length < 12) {
_months.push(date.toLocaleDateString(locale, { month: 'long' }))
date.setMonth(date.getMonth() + 1)
}
return { days: _days, months: _months }
}
function wrapAround(idx, array) {
var len = array.length
var n = idx >= len ? idx - len : idx
return array[n]
}
/***************************************
*
* generators
*
***************************************/
function daysFromLastMonth(props){
var month = props.date.getMonth(), year = props.date.getFullYear()
var firstDay = (new Date(year, month, 1)).getDay() - props.weekStart
if (firstDay < 0) firstDay += 7
var array = []
var lastDate = lastDateInMonth(props.date, -1)
var offsetStart = lastDate - firstDay + 1
for (var i=offsetStart; i<=lastDate; i++) { array.push(i) }
return array
}
function daysFromThisMonth(props) {
var max = lastDateInMonth(props.date, 0)
var array = []
for (var i=1; i<=max; i++) {
array.push(i)
}
return array
}
function daysFromNextMonth(prev, these) {
var soFar = prev.concat(these)
var mod = soFar.length % 7
var array = []
if (mod > 0) {
var n = 7 - mod
for (var i=1; i<=n; i++) { array.push(i) }
}
return array
}
function defaultDate() {
var now = new Date()
now.setHours(0, 0, 0, 0)
return now
}
function yearsForDecade(date) {
var year = date.getFullYear()
var array = []
var start = year - (year % 10)
for (var i=start; i<=start+10; i++) { array.push(i) }
return array
}
/***************************************
*
* view helpers
*
***************************************/
function classForBox(a, b) { return a === b ? 'chosen' : '' }
function displayDate(props) {
return props.date
.toLocaleDateString(props.locale, props.formatOptions || {
weekday: 'short',
month: 'short',
day: 'numeric',
year: 'numeric'
})
}
/***************************************
*
* components
*
***************************************/
var Header = {
view: function (vnode) {
var props = vnode.attrs.props
var date = props.date
var theseMonths = props.months || months
return m('.header'
// , m('.button-bg', { class: 'v' + props.view })
// , m('.fake-border')
, m('.button.prev'
, { onclick: prevNext.bind(null, props, -1) }
, prevNextTitles[props.view]
)
, m('.button.segment', { onclick: function () { props.view = 0 } }, m(".number", date.getDate()))
, m('.button.segment', { onclick: function () { props.view = 1 } }, m(".number", theseMonths[date.getMonth()].substr(0, 3)))
, m('.button.segment', { onclick: function () { props.view = 2 } }, m(".number", date.getFullYear()))
, m('.button.next'
, { onclick: prevNext.bind(null, props, 1) }
, prevNextTitles[props.view]
)
)
}
}
var MonthView = {
view: function (vnode) {
var props = vnode.attrs.props
var prevDates = daysFromLastMonth(props)
var theseDates = daysFromThisMonth(props)
var nextDates = daysFromNextMonth(prevDates, theseDates)
var theseWeekdays = props.days || days
return m('.calendar'
, m('.weekdays'
, theseWeekdays.map(function (_, idx) {
var day = wrapAround(idx + props.weekStart, theseWeekdays)
return m('.day.dummy', day.substring(0, 2))
})
)
, m('.weekdays'
, {
onclick: function(e){
chooseDate(props, e)
dismissAndCommit(props, vnode.attrs.onchange)
}
}
, prevDates.map(function (date) {
return m('.button.day.other-scope', m(".number", date))
})
, theseDates.map(function (date) {
return m('.button.day'
, { class: classForBox(props.date.getDate(), date) }
, m('.number', date)
)
})
, nextDates.map(function (date) {
return m('.button.day.other-scope', date)
})
)
)
}
}
var YearView = {
view: function (vnode) {
var props = vnode.attrs.props
var theseMonths = props.months || months
return m('.calendar'
, m('.months'
, theseMonths.map(function (month, idx) {
return m('.button.month'
, {
class: classForBox(props.date.getMonth(), idx),
onclick: function () {
var newDate = new Date(props.date)
newDate.setMonth(idx)
props.date = pushToLastDay(props.date, newDate)
props.view = 0
}
}
, m('.number', month.substring(0, 3))
)
})
)
)
}
}
var DecadeView = {
view: function (vnode) {
var props = vnode.attrs.props
var decade = yearsForDecade(props.date)
return m('.calendar'
, m('.years'
, {
style: {
display: "flex",
flexWrap: "wrap"
}
}
, decade.map(function (year) {
return m('.button.year'
, {
class: classForBox(props.date.getFullYear(), year),
onclick: function () {
var newDate = new Date(props.date)
newDate.setFullYear(year)
props.date = pushToLastDay(props.date, newDate)
props.view = 1
}
}
, m('.number', year)
)
})
)
)
}
}
var Editor = {
oncreate: function (vnode) {
requestAnimationFrame(function () { vnode.dom.classList.add('active') })
},
onbeforeremove: function (vnode) {
vnode.dom.classList.remove('active')
return new Promise(function (done) { setTimeout(done, 200) })
},
view: function (vnode) {
var props = vnode.attrs.props
return m('.editor'
, {
style: {
display: "table-cell",
verticalAlign: "middle"
}
}
, m(Header, { props: props })
, m('.sled'
, { class: 'p' + props.view }
, m(MonthView, { props: props, onchange: vnode.attrs.onchange })
, m(YearView, { props: props })
, m(DecadeView, {props: props })
)
)
}
}
var DatePicker = {
localize: function (loc) {
if (loc) {
prevNextTitles = loc.prevNextTitles || prevNextTitles
locale = loc.locale || locale
formatOptions = loc.formatOptions || formatOptions
weekStart = typeof loc.weekStart === 'number'
? loc.weekStart
: weekStart
var strings = stringsForLocale(locale)
days = strings.days
months = strings.months
}
},
oninit: function (vnode) {
var attrs = vnode.attrs
var props = {
date: new Date(attrs.date || defaultDate()),
active: false,
view: 0
}
;['prevNextTitles', 'locale', 'formatOptions'].forEach(function (prop) {
props[prop] = attrs[prop] || eval(prop)
})
props.weekStart = typeof attrs.weekStart === 'number' ? attrs.weekStart : weekStart
if (attrs.locale && attrs.locale !== locale) {
var strings = stringsForLocale(props.locale)
props.days = strings.days
props.months = strings.months
}
vnode.state.props = props
},
view: function(vnode){
var props = vnode.state.props
var displayText = displayDate(props)
return m('.mithril-date-picker-container'
, { class: props.active ? 'active' : '' }
, m('.mithril-date-picker'
, {
style: {
display: "table"
}
}
, m('.button.current-date'
, {
onclick: function(){
if (props.active) props.view = 0
props.active = !props.active
}
}
, displayText
)
, props.active && m('.overlay', { onclick: dismissAndCommit.bind(null, props, vnode.attrs.onchange) })
, props.active && m(Editor, { props: props, onchange: vnode.attrs.onchange })
)
)
}
}
if (typeof module === 'object') module.exports = DatePicker
else if (typeof window !== 'undefined') window.DatePicker = DatePicker
else global.DatePicker = DatePicker
})()

39
assets/js/index.js vendored Normal file
View File

@@ -0,0 +1,39 @@
import m from "mithril"
import { nav } from "./components/nav"
import { header } from "./components/header"
import { register, login, loginUser } from "./components/auth"
import { questionnaireList } from "./components/questionnaireList"
import { questionnaireList as clientQuestionnaireList } from "./components/client/questionnaireList"
import { questionnaire } from "./components/questionnaire"
import { questionnaire as clientQuestionnaire } from "./components/client/questionnaire"
import { editQuestionnaire } from "./components/editQuestionnaire"
import { section } from "./components/section"
import { editSection } from "./components/editSection"
import { question } from "./components/question"
import clientQuestion from "./components/client/question"
import { editQuestion } from "./components/editQuestion"
import signup from "./components/hello"
import {userList, userAll} from "./components/beta/userList"
m.route.prefix("#")
m.route(document.body, "/", {
"/": header,
"/auth": "/auth/register",
"/auth/register": register,
"/auth/login": login,
"/login": loginUser,
"/questionnaires": clientQuestionnaireList,
"/questionnaires/:id": clientQuestionnaire,
"/sections/:id": clientQuestion,
"/questions/:id": clientQuestion,
"/questions/:id/edit": editQuestion,
"/user/questionnaires": questionnaireList,
"/user/questionnaires/:id": questionnaire,
"/user/questionnaires/:id/edit": editQuestionnaire,
"/user/sections/:id": section,
"/user/sections/:id/edit": editSection,
"/user/questions/:id": question,
"/user/questions/:id/edit": editQuestion,
"/beta/departments/:id": userList,
"/beta/users": userAll
})

48
assets/js/models.bak/Answer.js vendored Normal file
View File

@@ -0,0 +1,48 @@
import m from "mithril"
export const Answer = {
list: [],
current: {},
message: "",
error: "",
fetchList: function() {
m.request({
method: "GET",
url: "/answers"
})
.then(function(res) {
Answer.list = res.data
})
},
fetchCurrent: function() {
m.request({
method: "GET",
url: "/answers/:id",
data: Answer.current
})
.then(function(res) {
Answer.current = res.data
})
},
upload: function() {
m.request({
method: "POST",
url: "/questions/:qId/anwers",
data: _.assign(Answer.current, {qId: Answer.current.question.id})
})
},
update: function() {
m.request({
method: "PUT",
url: "/answers/:id",
data: Answer.current
})
},
remove: function() {
m.request({
method: "DELETE",
url: "/answers/:id",
data: Answer.current
})
}
}

48
assets/js/models.bak/Choice.js vendored Normal file
View File

@@ -0,0 +1,48 @@
import m from "mithril"
export const Choice = {
list: [],
current: {},
message: "",
error: "",
fetchList: function() {
m.request({
method: "GET",
url: "/choices"
})
.then(function(res) {
Choice.list = res.data
})
},
fetchCurrent: function() {
m.request({
method: "GET",
url: "/choices/:id",
data: Choice.current
})
.then(function(res) {
Choice.current = res.data
})
},
upload: function() {
m.request({
method: "POST",
url: "/question/:qId/choices/",
data: _.assign(Choice.current, {qId: Choice.current.question.id})
})
},
update: function() {
m.request({
method: "PUT",
url: "/choices/:id",
data: Choice.current
})
},
remove: function() {
m.request({
method: "DELETE",
url: "/choices/:id",
data: Choice.current
})
}
}

76
assets/js/models.bak/Question.js vendored Normal file
View File

@@ -0,0 +1,76 @@
import m from "mithril"
export const Question = {
list: [],
current: {},
choices: [],
answers: [],
message: "",
error: "",
fetchList: function() {
m.request({
method: "GET",
url: "/questions"
})
.then(function(res) {
Question.list = res.data
})
},
fetchCurrent: function() {
m.request({
method: "GET",
url: "/questions/:id",
data: Question.current
})
.then(function(res) {
Question.current = res.data
})
},
fetchChoices: function() {
m.request({
method: "GET",
url: "/questions/:id/choices",
data: Question.current
})
.then(function(res) {
Question.choices = res.data
})
},
fetchAnswers: function() {
m.request({
method: "GET",
url: "/questions/:id/answers",
data: Question.current
})
.then(function(res) {
Question.answers = res.data
})
},
upload: function() {
m.request({
method: "POST",
url: "/sections/:sId/questions",
data: _.assign(Question.current, {sId: Question.current.section.id})
})
},
uploadChoice: function() {
},
uploadAnswer: function() {
},
update: function() {
m.request({
method: "PUT",
url: "/questions/:id",
data: Question.current
})
},
remove: function() {
m.request({
method: "DELETE",
url: "/questions/:id",
data: Question.current
})
}
}

76
assets/js/models.bak/Questionnaire.js vendored Normal file
View File

@@ -0,0 +1,76 @@
import m from "mithril"
export const Questionnaire = {
list: [],
current: {},
sections: [],
reports: [],
message: "",
error: "",
fetchList: function() {
m.request({
method: "GET",
url: "/questionnaires"
})
.then(function(res) {
Questionnaire.list = res.data
})
},
fetchCurrent: function() {
m.request({
method: "GET",
url: "/questionnaires/:id",
data: Questionnaire.current
})
.then(function(res) {
Questionnaire.current = res.data
})
},
fetchSections: function() {
m.request({
method: "GET",
url: "/questionnaires/:id/sections",
data: Questionnaire.current
})
.then(function(res) {
Questionnaire.sections = res.data
})
},
fetchReports: function() {
m.request({
method: "GET",
url: "/questionnaires/:id/reports",
data: Questionnaire.current
})
.then(function(res) {
Questionnaire.reports = res.data
})
},
upload: function() {
m.request({
method: "POST",
url: "/questionnaires",
data: Questionnaire.current
})
.then(function(res) {
Questionnaire.current = res.data
})
},
uploadSection: function() {
}
update: function() {
m.request({
method: "PUT",
url: "/questionnaires/:id",
data: Questionnaire.current
})
},
remove: function() {
m.request({
method: "DELETE",
url: "/questionnaires/:id",
data: Questionnaire.current
})
}
}

62
assets/js/models.bak/Section.js vendored Normal file
View File

@@ -0,0 +1,62 @@
import m from "mithril"
export const Section = {
list: [],
current: {},
questions: [],
message: "",
error: "",
fetchList: function() {
m.request({
method: "GET",
url: "/sections"
})
.then(function(res) {
Section.list = res.data
})
},
fetchCurrent: function() {
m.request({
method: "GET",
url: "/sections",
data: Section.current
})
.then(function(res) {
Section.current = res.data
})
},
fetchQuestions: function() {
m.request({
method: "GET",
url: "/sections/:id/questions",
data: Section.current
}).
then(function(res) {
Section.questions = res.data
})
},
upload: function() {
m.request({
method: "POST",
url: "/questionnaires/:qId/sections",
data: _.assign(Section.current, {qId: Section.current.questionnaire.id})
})
},
uploadQuestion: function() {
},
update: function() {
m.request({
method: "PUT",
url: "/sections/:id",
data: Section.current
})
},
remove: function() {
m.request({
method: "DELETE",
url: "/sections/:id",
data: Section.current
})
}
}

20
assets/js/models/Answer.js vendored Normal file
View File

@@ -0,0 +1,20 @@
import m from "mithril"
const Answer = {
list: [],
current: {},
loading: false,
fetch: function(answerId) {
Answer.loading = true
m.request({
url: "http://api.questionnaire.dev/v1/answers/" + answerId,
method: "GET"
})
.then(function(res) {
Answer.loading = false
console.log("response: ", res);
})
}
}
export default Answer

22
assets/js/models/Question.js vendored Normal file
View File

@@ -0,0 +1,22 @@
import m from "mithril"
const Question = {
current: {},
list: [],
loading: false,
fetchCurrent: function(sectionId, url) {
Question.loading = true
if (_.isNil(url)) url = "http://api.questionnaire.dev/v1/sections/" + sectionId + "/questions"
m.request({
url,
method: "GET",
})
.then(function(res) {
res.data = res.data[0]
Question.current = res
Question.loading = false
})
}
}
export default Question

32
assets/js/models/QuestionAnswer.js vendored Normal file
View File

@@ -0,0 +1,32 @@
import m from "mithril"
const QuestionAnswer = {
list: [],
current: {},
loading: false,
fetch: function(questionId) {
QuestionAnswer.loading = true
m.request({
url: "http://api.questionnaire.dev/v1/questions/" + questionId + "/answers",
method: "GET"
})
.then(function(res) {
QuestionAnswer.loading = false
console.log("response: ", res);
})
},
upload: function(questionId) {
QuestionAnswer.loading = true
m.request({
url: "http://api.questionnaire.dev/v1/questions/" + questionId + "/answers",
method: "POST",
data: QuestionAnswer.current
})
.then(function(res) {
QuestionAnswer.loading = false
console.log("response: ", res);
})
}
}
export default QuestionAnswer

31
assets/js/models/Questionnaire.js vendored Normal file
View File

@@ -0,0 +1,31 @@
import m from "mithril"
const Questionnaire = {
current: {},
list: [],
loading: false,
fetch: function(id) {
Questionnaire.loading = true
m.request({
url: "http://api.questionnaire.dev/v1/questionnaires/" + id,
method: "GET"
})
.then(function(res) {
Questionnaire.current = res
Questionnaire.loading = false
})
},
loadList: function() {
Questionnaire.loading = true
m.request({
url: "http://api.questionnaire.dev/v1/questionnaires",
method: "GET"
})
.then(function(res) {
Questionnaire.list = res.data
Questionnaire.loading = false
})
}
}
export default Questionnaire

View File

@@ -0,0 +1,20 @@
import m from "mithril"
const QuestionnaireSection = {
current: {},
list: [],
loading: false,
fetch: function(questionnaireId) {
QuestionnaireSection.loading = true
m.request({
url: "http://api.questionnaire.dev/v1/questionnaires/" + questionnaireId + "/sections",
method: "GET"
})
.then(function(res) {
QuestionnaireSection.current = res
QuestionnaireSection.loading = false
})
}
}
export default QuestionnaireSection

20
assets/js/models/Respondent.js vendored Normal file
View File

@@ -0,0 +1,20 @@
import m from "mithril"
const Respondent = {
list: [],
current: {},
loading: false,
fetch: function(id) {
Respondent.loading = true
m.request({
url: "http://api.questionnaire.dev/v1/respondents/" + id,
method: "GET"
})
.then(function(res) {
Respondent.current = res
Respondent.loading = false
})
}
}
export default Respondent

20
assets/js/models/Section.js vendored Normal file
View File

@@ -0,0 +1,20 @@
import m from "mithril"
const Section = {
current: {},
list: [],
loading: false,
fetch: function(id) {
Section.loading = true
m.request({
url: "http://api.questionnaire.dev/v1/sections/" + id,
method: "GET"
})
.then(function(res) {
Section.current = res
Section.loading = false
})
}
}
export default Section

33
assets/js/models/SectionQuestion.js vendored Normal file
View File

@@ -0,0 +1,33 @@
import m from "mithril"
const SectionQuestion = {
current: {},
list: [],
loading: false,
fetch: function(sectionId) {
SectionQuestion.loading = true
m.request({
url: "http://api.questionnaire.dev/v1/sections/" + sectionId + "/questions",
method: "GET"
})
.then(function(res) {
res.data = res.data[0]
SectionQuestion.current = res
SectionQuestion.loading = false
})
},
nextOrPrev: function(url) {
SectionQuestion.loading = true
m.request({
url,
method: "GET"
})
.then(function(res) {
res.data = res.data[0]
SectionQuestion.current = res
SectionQuestion.loading = false
})
}
}
export default SectionQuestion

74
assets/js/models/User.bak.js vendored Normal file
View File

@@ -0,0 +1,74 @@
import m from "mithril"
export const User = {
list: [],
current: {},
message: "",
error: "",
fetchList: function() {
m.request({
method: "GET",
url: ""
})
.then(function(res) {
User.list = res
})
.catch(function(e) {
User.error = e.message
})
},
fetchCurrent: function() {
m.request({
method: "GET",
url: ""
})
.then(function(res) {
User.current = res
})
.catch(function(e) {
User.error = e.message
})
},
regist: function() {
m.request({
method: "POST",
url: "",
data: User.current,
withCredentials: true
})
.then(function(res) {
User.message = res
})
.catch(function(e) {
User.error = e.message
})
},
login: function() {
m.request({
method: "GET",
url: "",
data: User.current,
withCredentials: true
})
.then(function(res) {
/* Must set header here*/
User.message = res
})
.catch(function(e) {
User.error = e.message
})
},
logout: function() {
m.request({
method: "GET",
url: "",
withCredentials: true
})
.then(function(res) {
User.message = res
})
.catch(function(e) {
User.error = e.message
})
}
}

32
assets/js/models/User.js vendored Normal file
View File

@@ -0,0 +1,32 @@
import m from "mithril"
const User = {
list: [],
current: {},
loading: false,
fetchList: function() {
User.list = require("../../json/users/example").data
},
fetchCurrent: function(userId) {
User.loading = true
m.request({
url: "http://api.questionnaire.dev/v1/users/" + userId,
method: "GET"
})
.then(function(res) {
User.current = res
User.loading = false
})
},
regist: function() {
},
login: function() {
m.route.set("/user/questionnaires")
},
logout: function() {
}
}
export default User

24
assets/js/models/beta/Dept.js vendored Normal file
View File

@@ -0,0 +1,24 @@
const Dept = {
list: [
{id: 1, name: "BPH Yayasan"},
{id: 2, name: "Sekretariat Yayasan"},
{id: 3, name: "HRD"},
{id: 4, name: "Keuangan"},
{id: 5, name: "Pimpinan Perguruan Tinggi"},
{id: 6, name: "LC & LPU"},
{id: 7, name: "Pelaksana Kerjasama"},
{id: 8, name: "Esbed"},
{id: 9, name: "Kemahasiswaan"},
{id: 10, name: "Kreatif"},
{id: 11, name: "Web & IT"},
{id: 12, name: "Humas"},
{id: 12, name: "TU SMK"},
{id: 13, name: "Marketing, Receptionist, and Student Adminision"},
{id: 14, name: "P3S dan Umum"},
{id: 15, name: "Lab. Komputer"},
{id: 16, name: "Satpam"}
],
current: {}
}
export default Dept

69
assets/js/models/beta/User.js vendored Normal file
View File

@@ -0,0 +1,69 @@
const User = {
list: [
{
id: 1,
name: "Dhimas",
dept: 11,
super: 1,
address: "Perum Paku Jaya Permai A2/8 007/05 Paku Jaya Tangerang",
birth: "Madiun, 2 Agustus 1990",
phone: "083895518773",
mail: "dhimas@lepisi.ac.id",
workEntry: "1 Maret 2012",
workPeriod: "4 tahun",
education: "S2 Sistem Informasi"
},
{
id: 2,
name: "Barsan",
dept: 11,
address: "Persada Raya J6/16 005/008 Gembor Tangerang",
birth: "Tangerang, 13 April 1996",
phone: "085892313773",
mail: "barsan@lepisi.ac.id",
workEntry: "4 Oktober 2017",
workPeriod: "2 bulan",
education: "S1 Teknik Informatika"
},
{
id: 3,
name: "Gregorio",
dept: 11,
address: "Jalan Cempaka III HQ/22 Bumi Indah Kab. Tangerang",
birth: "Tangerang, 23 Mei 1999",
phone: "085819967701",
mail: "gregorio@lepisi.ac.id",
workEntry: "1 Agustus 2017",
workPeriod: "4 bulan",
education: "S1 Teknik Informatika"
},
{
id: 4,
name: "Donny",
dept: 10,
address: "Jl. Pepaya Raya E/22 No. 15 05/17 Bumi Asri, Tangerang",
birth: "Tangerang, 14 Januari 1997",
phone: "083813154407",
mail: "donny@lepisi.ac.id",
workEntry: "25 Juni 2014",
workPeriod: "2 tahun",
education: "TK III STT"
},
{
id: 5,
name: "Widi",
dept: 10,
super: 1,
address: "Dasana Indah UD 4/26 No. 26 Tangerang",
birth: "Tangerang, 30 September 1995",
phone: "081298877765",
mail: "widi@lepisi.ac.id",
workEntry: "25 Juni 2014",
workPeriod: "2 tahun",
education: "TK III STT"
}
],
current: {}
}
export default User