Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
 
 
 
 
 
 

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