feat(avatar) : add avatar service, DTO update, and cropper dependency
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
37
frontend/package-lock.json
generated
37
frontend/package-lock.json
generated
@@ -18,6 +18,7 @@
|
|||||||
"nuxt-toast": "^1.4.0",
|
"nuxt-toast": "^1.4.0",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"vue": "^3.5.29",
|
"vue": "^3.5.29",
|
||||||
|
"vue-advanced-cropper": "^2.8.9",
|
||||||
"vue-chartjs": "^5.3.3",
|
"vue-chartjs": "^5.3.3",
|
||||||
"vue-router": "^4.6.4"
|
"vue-router": "^4.6.4"
|
||||||
}
|
}
|
||||||
@@ -6789,6 +6790,12 @@
|
|||||||
"consola": "^3.2.3"
|
"consola": "^3.2.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/classnames": {
|
||||||
|
"version": "2.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
|
||||||
|
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/clipboardy": {
|
"node_modules/clipboardy": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/clipboardy/-/clipboardy-4.0.0.tgz",
|
||||||
@@ -7301,6 +7308,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/debounce": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/debounce/-/debounce-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/debug": {
|
"node_modules/debug": {
|
||||||
"version": "4.4.3",
|
"version": "4.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||||
@@ -7578,6 +7591,12 @@
|
|||||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
|
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/easy-bem": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/easy-bem/-/easy-bem-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-GJRqdiy2h+EXy6a8E6R+ubmqUM08BK0FWNq41k24fup6045biQ8NXxoXimiwegMQvFFV3t1emADdGNL1TlS61A==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/ee-first": {
|
"node_modules/ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
@@ -13869,6 +13888,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/vue-advanced-cropper": {
|
||||||
|
"version": "2.8.9",
|
||||||
|
"resolved": "https://registry.npmjs.org/vue-advanced-cropper/-/vue-advanced-cropper-2.8.9.tgz",
|
||||||
|
"integrity": "sha512-1jc5gO674kVGpJKekoaol6ZlwaF5VYDLSBwBOUpViW0IOrrRsyLw6XNszjEqgbavvqinlKNS6Kqlom3B5M72Tw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"classnames": "^2.2.6",
|
||||||
|
"debounce": "^1.2.0",
|
||||||
|
"easy-bem": "^1.0.2"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=8",
|
||||||
|
"npm": ">=5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"vue": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/vue-bundle-renderer": {
|
"node_modules/vue-bundle-renderer": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/vue-bundle-renderer/-/vue-bundle-renderer-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/vue-bundle-renderer/-/vue-bundle-renderer-2.2.0.tgz",
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
"nuxt-toast": "^1.4.0",
|
"nuxt-toast": "^1.4.0",
|
||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"vue": "^3.5.29",
|
"vue": "^3.5.29",
|
||||||
|
"vue-advanced-cropper": "^2.8.9",
|
||||||
"vue-chartjs": "^5.3.3",
|
"vue-chartjs": "^5.3.3",
|
||||||
"vue-router": "^4.6.4"
|
"vue-router": "^4.6.4"
|
||||||
}
|
}
|
||||||
|
|||||||
24
frontend/services/avatar.ts
Normal file
24
frontend/services/avatar.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
export function useAvatarService() {
|
||||||
|
const api = useApi()
|
||||||
|
|
||||||
|
async function upload(userId: number, file: Blob): Promise<{ avatarUrl: string }> {
|
||||||
|
const formData = new FormData()
|
||||||
|
formData.append('file', file, 'avatar.png')
|
||||||
|
|
||||||
|
return $fetch(`/api/users/${userId}/avatar`, {
|
||||||
|
method: 'POST',
|
||||||
|
body: formData,
|
||||||
|
credentials: 'include',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function remove(userId: number): Promise<void> {
|
||||||
|
await api.delete(`/users/${userId}/avatar`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function getUrl(userId: number): string {
|
||||||
|
return `/api/users/${userId}/avatar`
|
||||||
|
}
|
||||||
|
|
||||||
|
return { upload, remove, getUrl }
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ export type UserData = {
|
|||||||
roles: string[]
|
roles: string[]
|
||||||
client?: { id: number; name: string } | null
|
client?: { id: number; name: string } | null
|
||||||
allowedProjects?: Project[]
|
allowedProjects?: Project[]
|
||||||
|
avatarUrl?: string | null
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserWrite = {
|
export type UserWrite = {
|
||||||
|
|||||||
@@ -58,6 +58,14 @@ export const useAuthStore = defineStore('auth', {
|
|||||||
this.checked = true
|
this.checked = true
|
||||||
this.isLoading = false
|
this.isLoading = false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
async refreshUser() {
|
||||||
|
try {
|
||||||
|
const me = await getCurrentUser()
|
||||||
|
this.user = me
|
||||||
|
} catch {
|
||||||
|
// Silently fail — user session might have expired
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user