Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.
 
 
 
 
 
 

267 satır
5.8 KiB

  1. <template>
  2. <div class="panel">
  3. <template v-if="user">
  4. <side-bar v-if="user" :role="user && user.status" :active="active">
  5. </side-bar>
  6. <div v-if="loading" class="page loading">
  7. <span class="error" >{{loadingError}}</span>
  8. <spinner></spinner>
  9. </div>
  10. <home :user="user" v-else-if="active == 1" />
  11. <new-estimate
  12. :user="user"
  13. :fees="fees"
  14. :token="token"
  15. v-else-if="active == 2" />
  16. <estimates
  17. :user="user"
  18. :fees="fees"
  19. v-else-if="active == 3"
  20. :token="token"
  21. @addFeeTemp="(f) => fees.push(f)"
  22. @removeFeeTemp="(fee) => fees = fees.filter(f => f.id != fee.id)"
  23. />
  24. <settings
  25. :user="user"
  26. :token="token"
  27. @updateAvatar="updateAvatar"
  28. @updateLetterhead="updateLetterhead"
  29. v-else-if="active == 4" />
  30. <sign-out :user="user" v-else-if="active == 5" />
  31. </template>
  32. <template v-if="!user && active == 6">
  33. <login @login="start" />
  34. </template>
  35. </div>
  36. </template>
  37. <script>
  38. import SideBar from "./sidebar.vue"
  39. import Spinner from "./spinner.vue"
  40. import Home from "./home.vue"
  41. import NewEstimate from "./new/new.vue"
  42. import Estimates from "./estimates.vue"
  43. import Settings from "./settings.vue"
  44. import SignOut from "./sign-out.vue"
  45. import Login from "./login.vue"
  46. function getCookie(name) {
  47. var re = new RegExp(name + "=([^;]+)")
  48. var value = re.exec(document.cookie)
  49. return (value != null) ? unescape(value[1]) : null
  50. }
  51. function refreshToken() {
  52. const token = getCookie("skouter")
  53. const timeout = setTimeout(this.refreshToken, 1000*60*25)
  54. fetch(`/api/token`,
  55. {method: 'GET',
  56. headers: {
  57. "Accept": "application/json",
  58. "Authorization": `Bearer ${token}`,
  59. },
  60. }).then(response => {
  61. if (!response.ok) {
  62. console.log("Error refreshing token.")
  63. clearTimeout(timeout)
  64. window.location.hash = '#login'
  65. } else {
  66. this.token = getCookie("skouter")
  67. }
  68. })
  69. }
  70. function getUser() {
  71. const token = getCookie("skouter")
  72. this.token = token
  73. return fetch(`/api/user`,
  74. {method: 'GET',
  75. headers: {
  76. "Accept": "application/json",
  77. "Authorization": `Bearer ${token}`,
  78. },
  79. }).then(response => {
  80. if (response.ok) {
  81. return response.json()
  82. } else {
  83. // Redirect to login if starting token is invalid
  84. window.location.hash = '#login'
  85. }
  86. }).then (result => {
  87. if (!result || !result.length) return // Exit if token is invalid
  88. this.user = result[0]
  89. if (this.user.avatar) return
  90. return getAvatar(token)
  91. }).then(b => {
  92. const validTypes = ['image/jpeg', 'image/png']
  93. if (!validTypes.includes(b.type) || b.size <= 1) {
  94. fetch("/assets/image/empty-avatar.jpg").
  95. then(r => r.blob()).then( a => this.user.avatar = a )
  96. return
  97. }
  98. this.user.avatar = b
  99. return getLetterhead(token)
  100. }).then(b => {
  101. const validTypes = ['image/jpeg', 'image/png']
  102. if (!validTypes.includes(b.type) || b.size <= 1) {
  103. fetch("/assets/image/empty-letterhead.jpg").
  104. then(r => r.blob()).then( a => this.user.letterhead = a )
  105. return
  106. }
  107. this.user.letterhead = b
  108. })
  109. }
  110. function getAvatar(t) {
  111. return fetch("/api/user/avatar",
  112. {method: 'GET',
  113. headers: {
  114. "Accept": "application/json",
  115. "Authorization": `Bearer ${t || this.token}`,
  116. }
  117. }).then(r => r.blob())
  118. }
  119. function getLetterhead(t) {
  120. return fetch("/api/user/letterhead",
  121. {method: 'GET',
  122. headers: {
  123. "Accept": "application/json",
  124. "Authorization": `Bearer ${t || this.token}`,
  125. }
  126. }).then(r => r.blob())
  127. }
  128. function updateAvatar() {
  129. const token = getCookie("skouter")
  130. getAvatar(token).then(b => this.user.avatar = b)
  131. }
  132. function updateLetterhead() {
  133. const token = getCookie("skouter")
  134. getLetterhead(token).then(b => this.user.letterhead = b)
  135. }
  136. function getFees() {
  137. const token = getCookie("skouter")
  138. return fetch(`/api/fees`,
  139. {method: 'GET',
  140. headers: {
  141. "Accept": "application/json",
  142. "Authorization": `Bearer ${token}`,
  143. },
  144. }).then(response => {
  145. if (response.ok) { return response.json() }
  146. }).then (result => {
  147. if (!result || !result.length) return // Exit if token is invalid or no fees are saved
  148. this.fees = result
  149. })
  150. }
  151. // Used to check the current section of the app generally without a regex match
  152. // each time.
  153. function active() {
  154. if (this.hash == '' || this.hash == '#') {
  155. return 1
  156. } else if (/^#new\/?/.exec(this.hash)) {
  157. return 2
  158. } else if (/^#estimates\/?/.exec(this.hash)) {
  159. return 3
  160. } else if (/^#settings\/?/.exec(this.hash)) {
  161. return 4
  162. } else if (/^#sign-out\/?/.exec(this.hash)) {
  163. return 5
  164. } else if (/^#login\/?/.exec(this.hash)) {
  165. return 6
  166. } else {
  167. return 0
  168. }
  169. }
  170. // Fetch data before showing UI. If requests fail, assume token is expired.
  171. function start() {
  172. this.loading = true
  173. let loaders = []
  174. loaders.push(this.getUser())
  175. loaders.push(this.getFees())
  176. Promise.all(loaders).then((a, b) => {
  177. this.loading = false
  178. if (!b) {
  179. // Time untill token expiration may have elapsed before the page
  180. // reloaded
  181. this.refreshToken()
  182. }
  183. }).catch(error => {
  184. console.log("An error occured %O", error)
  185. this.loadingError = "Could not initialize app."
  186. window.location.hash = 'login'
  187. })
  188. }
  189. export default {
  190. components: {
  191. SideBar,
  192. Spinner,
  193. Home,
  194. NewEstimate,
  195. Estimates,
  196. Settings,
  197. SignOut,
  198. Login
  199. },
  200. computed: { active },
  201. methods: {
  202. getCookie,
  203. start,
  204. getUser,
  205. getFees,
  206. refreshToken,
  207. updateAvatar,
  208. getAvatar,
  209. updateLetterhead,
  210. getLetterhead,
  211. },
  212. data() {
  213. return {
  214. loading: true,
  215. user: null,
  216. hash: window.location.hash,
  217. fees: [],
  218. loadingError: "",
  219. token: '',
  220. }
  221. },
  222. created() {
  223. window.onhashchange = () => this.hash = window.location.hash
  224. this.token = this.getCookie("skouter")
  225. if (!this.token) {
  226. window.location.hash = 'login'
  227. this.loading = false
  228. return
  229. }
  230. this.start()
  231. }
  232. }
  233. </script>