Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 
 
 

291 строка
6.2 KiB

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