Files
hnh-map/frontend-nuxt/pages/admin/users/[username].vue
Nikolay Tatarinov fd624c2357 Refactor frontend components for improved functionality and accessibility
- Consolidated global error handling in app.vue to redirect users to the login page on API authentication failure.
- Enhanced MapView component by reintroducing event listeners for selected map and marker updates, improving interactivity.
- Updated PasswordInput and various modal components to ensure proper input handling and accessibility compliance.
- Refactored MapControls and MapControlsContent to streamline prop management and enhance user experience.
- Improved error handling in local storage operations within useMapBookmarks and useRecentLocations composables.
- Standardized input elements across forms for consistency in user interaction.
2026-03-04 14:06:27 +03:00

127 lines
3.8 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="container mx-auto p-4 max-w-2xl min-w-0">
<h1 class="text-2xl font-bold mb-6">{{ isNew ? 'New user' : `Edit ${username}` }}</h1>
<form class="flex flex-col gap-4" @submit.prevent="submit">
<fieldset class="fieldset">
<label class="label" for="user">Username</label>
<input
id="user"
v-model="form.user"
type="text"
class="input min-h-11 touch-manipulation"
required
:readonly="!isNew"
>
</fieldset>
<p id="admin-user-password-hint" class="text-sm text-base-content/60 mb-1">Leave blank to keep current password.</p>
<PasswordInput
v-model="form.pass"
label="Password"
autocomplete="new-password"
aria-describedby="admin-user-password-hint"
/>
<fieldset class="fieldset">
<label class="label">Auths</label>
<div class="flex flex-wrap gap-2">
<label v-for="a of authOptions" :key="a" class="label cursor-pointer gap-2" :for="`auth-${a}`">
<input :id="`auth-${a}`" v-model="form.auths" type="checkbox" :value="a" class="checkbox checkbox-sm" >
<span>{{ a }}</span>
</label>
</div>
</fieldset>
<p v-if="error" class="text-error text-sm">{{ error }}</p>
<div class="flex gap-2">
<button type="submit" class="btn btn-primary min-h-11 touch-manipulation" :disabled="loading">
<span v-if="loading" class="loading loading-spinner loading-sm" />
<span v-else>Save</span>
</button>
<NuxtLink to="/admin" class="btn btn-ghost min-h-11 touch-manipulation">Back</NuxtLink>
<button
v-if="!isNew"
type="button"
class="btn btn-error btn-outline ml-auto min-h-11 touch-manipulation"
:disabled="loading"
@click="confirmDelete"
>
Delete
</button>
</div>
</form>
<ConfirmModal
v-model="showDeleteModal"
title="Delete user"
:message="`Delete user ${form.user}?`"
confirm-label="Delete"
:danger="true"
:loading="deleting"
@confirm="doDelete"
/>
</div>
</template>
<script setup lang="ts">
definePageMeta({ middleware: 'admin' })
useHead({ title: 'User HnH Map' })
const route = useRoute()
const router = useRouter()
const api = useMapApi()
const username = computed(() => (route.params.username as string) ?? '')
const isNew = computed(() => username.value === 'new')
const form = ref({ user: '', pass: '', auths: [] as string[] })
const authOptions = ['admin', 'map', 'markers', 'upload']
const loading = ref(false)
const deleting = ref(false)
const error = ref('')
const showDeleteModal = ref(false)
onMounted(async () => {
if (!isNew.value) {
form.value.user = username.value
try {
const u = await api.adminUserByName(username.value)
form.value.auths = u.auths ?? []
} catch {
error.value = 'Failed to load user'
}
}
})
async function submit() {
error.value = ''
loading.value = true
try {
await api.adminUserPost({
user: form.value.user,
pass: form.value.pass || undefined,
auths: form.value.auths,
})
await router.push('/admin')
} catch (e: unknown) {
error.value = e instanceof Error ? e.message : 'Failed'
} finally {
loading.value = false
}
}
function confirmDelete() {
showDeleteModal.value = true
}
async function doDelete() {
deleting.value = true
try {
await api.adminUserDelete(form.value.user)
showDeleteModal.value = false
await router.push('/admin')
} catch (e: unknown) {
error.value = e instanceof Error ? e.message : 'Delete failed'
} finally {
deleting.value = false
}
}
</script>