Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

195 lines
4.8 KiB

  1. <template>
  2. <div class="page settings">
  3. <h2>Settings</h2>
  4. <section class="form inputs">
  5. <h3>Avatar</h3>
  6. <canvas class="displayer" width="200" height="200" ref="avatar"></canvas>
  7. <input type="file"
  8. @change="e => changeAvatar(e.target.files[0])"
  9. />
  10. <button @click="uploadAvatar">Upload</button>
  11. <label class="error">{{avatarError}}</label>
  12. </section>
  13. <section class="form inputs letterhead">
  14. <h3>Letterhead</h3>
  15. <canvas class="displayer" height="200" ref="letterhead"></canvas>
  16. <input type="file"
  17. @change="e => {setLetterhead(e.target.files[0])}"
  18. />
  19. <button @click="uploadLetterhead">Upload</button>
  20. <label class="error">{{letterheadError}}</label>
  21. </section>
  22. <section class="form inputs special">
  23. <h3>Profile</h3>
  24. <label for="">First Name</label>
  25. <input type="text" v-model="user.firstName">
  26. <label for="">Last Name</label>
  27. <input type="text" :value="user.lastName">
  28. <label for="">NMLS ID</label>
  29. <input type="text">
  30. <label for="">Branch ID</label>
  31. <input type="text" :value="user.branchId">
  32. <select id="" name="" :value="user.country">
  33. <option value="USA">USA</option>
  34. <option value="Canada">Canada</option>
  35. </select>
  36. <button @click="saveProfile">Save</button>
  37. </section>
  38. <section class="form inputs special">
  39. <h3>Login</h3>
  40. <label for="">Email</label>
  41. <input type="text">
  42. <label for="">New Password</label>
  43. <input type="text">
  44. <button @click="check">Save</button>
  45. </section>
  46. <Dialog v-if="ready" @close="() => ready = false">
  47. <h3>Confirm your current password to save changes.</h3>
  48. <input type="text">
  49. <button>Confirm</button>
  50. </Dialog>
  51. </div>
  52. </template>
  53. <script setup>
  54. import { ref, watch, onMounted } from "vue"
  55. import Dialog from "./dialog.vue"
  56. let avatar = ref(null) // the canvas element
  57. let letterhead = ref(null) // the canvas element
  58. let ready = ref(false)
  59. let avatarChanged = ref(false)
  60. let avatarError = ref('')
  61. let letterHeadError = ref('')
  62. let letterheadError = ref('')
  63. const props = defineProps(['user', 'token'])
  64. const emit = defineEmits(['updateAvatar', 'updateLetterhead'])
  65. let user = Object.assign({}, props.user)
  66. function save() {
  67. }
  68. function check() {
  69. ready.value = true
  70. }
  71. function uploadAvatar() {
  72. avatar.value.toBlob(b => {
  73. fetch(`/api/user/avatar`,
  74. {method: 'POST',
  75. body: b,
  76. headers: {
  77. "Accept": "application/json",
  78. "Authorization": `Bearer ${props.token}`,
  79. },
  80. }).then(resp => {
  81. if (resp.ok) {emit('updateAvatar')}
  82. })
  83. })
  84. }
  85. function uploadLetterhead() {
  86. letterhead.value.toBlob(b => {
  87. fetch(`/api/user/letterhead`,
  88. {method: 'POST',
  89. body: b,
  90. headers: {
  91. "Accept": "application/json",
  92. "Authorization": `Bearer ${props.token}`,
  93. },
  94. }).then(resp => {
  95. if (resp.ok) {emit('updateLetterhead')}
  96. })
  97. })
  98. }
  99. function setLetterhead(f) {
  100. const validTypes = ['image/jpeg', 'image/png']
  101. if (!validTypes.includes(f.type)) {
  102. letterheadError.value = 'Image must be JPEG of PNG format'
  103. return
  104. }
  105. fetch(`/api/letterhead`,
  106. {method: 'POST',
  107. body: f,
  108. headers: {
  109. "Accept": "application/json",
  110. "Authorization": `Bearer ${props.token}`,
  111. },
  112. }).then(resp => {
  113. if (resp.ok) {
  114. resp.blob().then(b => changeLetterhead(b))
  115. } else {
  116. resp.text().then(e => letterheadError.value = e)
  117. }
  118. })
  119. }
  120. function changeAvatar(blob) {
  121. const validTypes = ['image/jpeg', 'image/png']
  122. if (!validTypes.includes(blob.type)) {
  123. avatarError.value = 'Image must be JPEG of PNG format'
  124. return
  125. }
  126. avatarError.value = ''
  127. createImageBitmap(blob,
  128. {resizeWidth: 200, resizeHeight: 200, resizeQuality: 'medium'}).
  129. then((img) => {
  130. avatar.value.getContext("2d").drawImage(img, 0, 0, 200, 200)
  131. })
  132. }
  133. function changeLetterhead(blob) {
  134. const validTypes = ['image/jpeg', 'image/png']
  135. if (!validTypes.includes(blob.type)) {
  136. letterheadError.value = 'Image must be JPEG of PNG format'
  137. return
  138. }
  139. createImageBitmap(blob).
  140. then((img) => {
  141. let ctx = letterhead.value.getContext("2d")
  142. ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
  143. ctx.drawImage(img, 0, 0)
  144. })
  145. }
  146. function saveProfile() {
  147. console.log(user.firstName)
  148. fetch(`/api/user`,
  149. {method: 'PATCH',
  150. body: JSON.stringify(user),
  151. headers: {
  152. "Accept": "application/json",
  153. "Authorization": `Bearer ${props.token}`,
  154. },
  155. }).then(resp => {
  156. if (resp.ok) {}
  157. })
  158. }
  159. watch(props.user, (u) => {
  160. if (props.user.avatar) {
  161. changeAvatar(props.user.avatar)
  162. }
  163. if (props.user.letterhead) {
  164. changeLetterhead(props.user.letterhead)
  165. }
  166. }, {immediate: true})
  167. </script>