Files
Inventory/app/components/sites/SiteCard.vue
Matthieu cc70fe2b29 feat(permissions) : add role-based UI guards and readonly mode for viewers
- Add usePermissions composable (isAdmin, canEdit, canView)
- Password-protected profile login with modal on profiles page
- Disable all form fields for ROLE_VIEWER across edit/create pages
- Show navigation buttons (Modifier/Consulter) for all roles, hide delete for viewers
- Add readonly prop to ModelTypeForm for category pages
- Disable modal fields (sites, constructeurs) for viewers
- Guard /admin routes in middleware

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 13:36:42 +01:00

76 lines
2.4 KiB
Vue

<template>
<div class="card bg-base-100 shadow-lg hover:shadow-xl transition-shadow">
<div class="card-body">
<div class="flex items-center justify-between mb-4">
<h3 class="card-title text-lg">
{{ site.name }}
</h3>
<div class="badge badge-primary badge-sm">
{{ machineCount }} machines
</div>
</div>
<div class="space-y-3 text-sm">
<div class="flex items-center gap-2 text-gray-700">
<IconLucideUser class="w-4 h-4 text-primary" aria-hidden="true" />
<span class="font-medium">{{ site.contactName }}</span>
</div>
<div class="flex items-center gap-2 text-gray-600">
<IconLucidePhone class="w-4 h-4 text-secondary" aria-hidden="true" />
<span>{{ formattedContactPhone }}</span>
</div>
<div class="flex items-start gap-2 text-gray-600">
<IconLucideMapPin class="w-4 h-4 text-accent mt-1" aria-hidden="true" />
<span>
{{ site.contactAddress }}<br>
{{ site.contactPostalCode }} {{ site.contactCity }}
</span>
</div>
<div class="flex items-center gap-2 text-gray-600">
<IconLucideFactory class="w-4 h-4 text-blue-500" aria-hidden="true" />
<span>{{ machineCount }} machine(s)</span>
</div>
</div>
<div class="card-actions justify-end mt-4">
<button class="btn btn-sm btn-outline" @click="emit('edit', site)">
{{ canEdit ? 'Modifier' : 'Consulter' }}
</button>
<button v-if="canEdit" class="btn btn-sm btn-error" @click="emit('delete', site)">
Supprimer
</button>
</div>
</div>
</div>
</template>
<script setup>
import { computed } from 'vue'
import IconLucideFactory from '~icons/lucide/factory'
import IconLucideMapPin from '~icons/lucide/map-pin'
import IconLucidePhone from '~icons/lucide/phone'
import IconLucideUser from '~icons/lucide/user'
import { formatPhone } from '~/utils/formatters/phone'
const { canEdit } = usePermissions()
const props = defineProps({
site: {
type: Object,
required: true
}
})
const emit = defineEmits(['edit', 'delete'])
const machineCount = computed(() => props.site?.machines?.length || 0)
const formattedContactPhone = computed(() => {
const value = props.site?.contactPhone ?? ''
const formatted = formatPhone(value)
return formatted || value || '—'
})
</script>