|
11 | 11 |
|
12 | 12 | <div class="form-group"> |
13 | 13 | <label>Username:</label> |
14 | | - <input type="text" :value="userStore.username" disabled class="input-field" /> |
| 14 | + <div class="username-edit-group"> |
| 15 | + <input |
| 16 | + type="text" |
| 17 | + v-model="editUsername" |
| 18 | + :disabled="!isEditing" |
| 19 | + class="input-field" |
| 20 | + :class="{ 'editing': isEditing }" |
| 21 | + /> |
| 22 | + <div class="edit-actions"> |
| 23 | + <button v-if="!isEditing" @click="startEditing" class="edit-btn">Edit</button> |
| 24 | + <div v-else class="action-buttons"> |
| 25 | + <button @click="saveUsername" class="save-btn" :disabled="isSaving"> |
| 26 | + {{ isSaving ? 'Saving...' : 'Save' }} |
| 27 | + </button> |
| 28 | + <button @click="cancelEditing" class="cancel-btn" :disabled="isSaving">Cancel</button> |
| 29 | + </div> |
| 30 | + </div> |
| 31 | + </div> |
15 | 32 | </div> |
16 | 33 |
|
17 | 34 | <button class="logout-btn" @click="handleLogout"> |
@@ -64,6 +81,43 @@ const router = useRouter(); |
64 | 81 | const userStore = useUserStore(); |
65 | 82 | const notificationStore = useInAppNotificationStore(); |
66 | 83 | const { isMuted } = storeToRefs(notificationStore); |
| 84 | +import { useToastStore } from '../stores/toast.store'; |
| 85 | +
|
| 86 | +const toastStore = useToastStore(); |
| 87 | +const isEditing = ref(false); |
| 88 | +const isSaving = ref(false); |
| 89 | +const editUsername = ref(userStore.username); |
| 90 | +
|
| 91 | +const startEditing = () => { |
| 92 | + editUsername.value = userStore.username; |
| 93 | + isEditing.value = true; |
| 94 | +}; |
| 95 | +
|
| 96 | +const cancelEditing = () => { |
| 97 | + isEditing.value = false; |
| 98 | + editUsername.value = userStore.username; |
| 99 | +}; |
| 100 | +
|
| 101 | +const saveUsername = async () => { |
| 102 | + if (!editUsername.value.trim() || editUsername.value === userStore.username) { |
| 103 | + isEditing.value = false; |
| 104 | + return; |
| 105 | + } |
| 106 | + |
| 107 | + try { |
| 108 | + isSaving.value = true; |
| 109 | + await userStore.updateProfile(editUsername.value); |
| 110 | + toastStore.add('Username updated successfully', 'success'); |
| 111 | + isEditing.value = false; |
| 112 | + } catch (error: any) { |
| 113 | + // Show specific error feedback |
| 114 | + const errorMessage = error.response?.data?.error || "Failed to update username"; |
| 115 | + toastStore.add(errorMessage, 'error'); |
| 116 | + console.error("Failed to update username", error); |
| 117 | + } finally { |
| 118 | + isSaving.value = false; |
| 119 | + } |
| 120 | +}; |
67 | 121 |
|
68 | 122 | const currentTheme = ref('light'); |
69 | 123 |
|
@@ -267,4 +321,47 @@ const toggleNotifications = () => { |
267 | 321 | padding: 1.5rem; |
268 | 322 | } |
269 | 323 | } |
| 324 | +
|
| 325 | +/* Edit Styles */ |
| 326 | +.username-edit-group { |
| 327 | + display: flex; |
| 328 | + gap: 1rem; |
| 329 | + align-items: center; |
| 330 | +} |
| 331 | +
|
| 332 | +.edit-actions { |
| 333 | + display: flex; |
| 334 | + align-items: center; |
| 335 | +} |
| 336 | +
|
| 337 | +.action-buttons { |
| 338 | + display: flex; |
| 339 | + gap: 0.5rem; |
| 340 | +} |
| 341 | +
|
| 342 | +.edit-btn, .cancel-btn { |
| 343 | + padding: 0.5rem 1rem; |
| 344 | + background: transparent; |
| 345 | + border: 1px solid var(--color-border); |
| 346 | + border-radius: 4px; |
| 347 | + color: var(--color-text); |
| 348 | + cursor: pointer; |
| 349 | + font-size: 0.85rem; |
| 350 | +} |
| 351 | +
|
| 352 | +.save-btn { |
| 353 | + padding: 0.5rem 1rem; |
| 354 | + background: #10b981; |
| 355 | + border: none; |
| 356 | + border-radius: 4px; |
| 357 | + color: white; |
| 358 | + cursor: pointer; |
| 359 | + font-size: 0.85rem; |
| 360 | +} |
| 361 | +
|
| 362 | +.save-btn:disabled { |
| 363 | + opacity: 0.7; |
| 364 | + cursor: not-allowed; |
| 365 | +} |
| 366 | +
|
270 | 367 | </style> |
0 commit comments