Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 
 

230 wiersze
5.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>Reset Password</h3>
  40. <label for="">Old Password</label>
  41. <input type="password" v-model="oldPass">
  42. <label for="">New Password</label>
  43. <input type="password" v-model="newPass">
  44. <label for="">Confirm Password</label>
  45. <input type="password" v-model="confirmPass">
  46. <button
  47. :disabled="!(oldPass && newPass && confirmPass)"
  48. @click="changePassword">Save</button>
  49. <label class="error">{{passError}}</label>
  50. </section>
  51. <Dialog v-if="ready" @close="() => ready = false">
  52. <h3>Confirm your current password to save changes.</h3>
  53. <input type="text">
  54. <button>Confirm</button>
  55. </Dialog>
  56. </div>
  57. </template>
  58. <script setup>
  59. import { ref, watch, onMounted } from "vue"
  60. import Dialog from "./dialog.vue"
  61. let avatar = ref(null) // the canvas element
  62. let letterhead = ref(null) // the canvas element
  63. let ready = ref(false)
  64. let avatarChanged = ref(false)
  65. let avatarError = ref('')
  66. let letterheadError = ref('')
  67. let passError = ref('')
  68. let oldPass = ref('')
  69. let newPass = ref('')
  70. let confirmPass = ref('')
  71. const props = defineProps(['user', 'token'])
  72. const emit = defineEmits(['updateAvatar', 'updateLetterhead'])
  73. let user = Object.assign({}, props.user)
  74. function save() {
  75. }
  76. function check() {
  77. ready.value = true
  78. }
  79. function uploadAvatar() {
  80. avatar.value.toBlob(b => {
  81. fetch(`/api/user/avatar`,
  82. {method: 'POST',
  83. body: b,
  84. headers: {
  85. "Accept": "application/json",
  86. "Authorization": `Bearer ${props.token}`,
  87. },
  88. }).then(resp => {
  89. if (resp.ok) {emit('updateAvatar')}
  90. })
  91. })
  92. }
  93. function uploadLetterhead() {
  94. letterhead.value.toBlob(b => {
  95. fetch(`/api/user/letterhead`,
  96. {method: 'POST',
  97. body: b,
  98. headers: {
  99. "Accept": "application/json",
  100. "Authorization": `Bearer ${props.token}`,
  101. },
  102. }).then(resp => {
  103. if (resp.ok) {emit('updateLetterhead')}
  104. })
  105. })
  106. }
  107. function setLetterhead(f) {
  108. letterheadError.value = ""
  109. const validTypes = ['image/jpeg', 'image/png']
  110. if (!validTypes.includes(f.type)) {
  111. letterheadError.value = 'Image must be JPEG of PNG format'
  112. return
  113. }
  114. fetch(`/api/letterhead`,
  115. {method: 'POST',
  116. body: f,
  117. headers: {
  118. "Accept": "application/json",
  119. "Authorization": `Bearer ${props.token}`,
  120. },
  121. }).then(resp => {
  122. if (resp.ok) {
  123. resp.blob().then(b => changeLetterhead(b))
  124. } else {
  125. resp.text().then(e => letterheadError.value = e)
  126. }
  127. })
  128. }
  129. function changeAvatar(blob) {
  130. const validTypes = ['image/jpeg', 'image/png']
  131. if (!validTypes.includes(blob?.type)) {
  132. avatarError.value = 'Image must be JPEG of PNG format'
  133. return
  134. }
  135. avatarError.value = ''
  136. createImageBitmap(blob,
  137. {resizeWidth: 200, resizeHeight: 200, resizeQuality: 'medium'}).
  138. then((img) => {
  139. avatar.value.getContext("2d").drawImage(img, 0, 0, 200, 200)
  140. })
  141. }
  142. function changeLetterhead(blob) {
  143. const validTypes = ['image/jpeg', 'image/png']
  144. if (!validTypes.includes(blob.type)) {
  145. letterheadError.value = 'Image must be JPEG of PNG format'
  146. return
  147. }
  148. createImageBitmap(blob).
  149. then((img) => {
  150. let ctx = letterhead.value.getContext("2d")
  151. ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height)
  152. ctx.drawImage(img, 0, 0)
  153. })
  154. }
  155. function saveProfile() {
  156. console.log(user.firstName)
  157. fetch(`/api/user`,
  158. {method: 'PATCH',
  159. body: JSON.stringify(user),
  160. headers: {
  161. "Accept": "application/json",
  162. "Authorization": `Bearer ${props.token}`,
  163. },
  164. }).then(resp => {
  165. if (resp.ok) {}
  166. })
  167. }
  168. function changePassword(f) {
  169. fetch(`/api/user/password`,
  170. {method: 'POST',
  171. body: JSON.stringify({
  172. old: oldPass.value,
  173. new: newPass.value,
  174. confirm: confirmPass.value,
  175. }),
  176. headers: {
  177. "Accept": "application/json",
  178. "Authorization": `Bearer ${props.token}`,
  179. },
  180. }).then(resp => {
  181. if (resp.ok) {
  182. resp.blob().then(b => {
  183. oldPass.value = ""
  184. newPass.value = ""
  185. confirmPass.value = ""
  186. passError.value = ""
  187. })
  188. } else {
  189. resp.text().then(e => passError.value = e)
  190. }
  191. })
  192. }
  193. watch(props.user, (u) => {
  194. if (props.user.avatar) {
  195. changeAvatar(props.user.avatar)
  196. }
  197. if (props.user.letterhead) {
  198. changeLetterhead(props.user.letterhead)
  199. }
  200. }, {immediate: true})
  201. </script>