generated from corrad-software/corrad-af-2024
235 lines
7.6 KiB
Vue
235 lines
7.6 KiB
Vue
<script setup>
|
|
import { ref, computed } from 'vue';
|
|
import { useDmsStore } from '~/stores/dms';
|
|
|
|
const props = defineProps({
|
|
item: {
|
|
type: Object,
|
|
required: true
|
|
},
|
|
visible: {
|
|
type: Boolean,
|
|
default: false
|
|
}
|
|
});
|
|
|
|
const emit = defineEmits(['close', 'submit']);
|
|
|
|
// Store
|
|
const dmsStore = useDmsStore();
|
|
|
|
// Form state
|
|
const selectedAccessType = ref('view');
|
|
const accessDuration = ref('7 days');
|
|
const justification = ref('');
|
|
const isSubmitting = ref(false);
|
|
const formError = ref('');
|
|
|
|
// Access type options
|
|
const accessTypes = [
|
|
{ id: 'view', label: 'View Only', description: 'Can only view the document' },
|
|
{ id: 'download', label: 'Download', description: 'Can view and download' },
|
|
{ id: 'print', label: 'Print', description: 'Can view and print' },
|
|
{ id: 'full', label: 'Full Access', description: 'View, download and print' }
|
|
];
|
|
|
|
// Access duration options
|
|
const durationOptions = [
|
|
'7 days',
|
|
'14 days',
|
|
'30 days',
|
|
'60 days',
|
|
'90 days',
|
|
'Permanent'
|
|
];
|
|
|
|
// Computed properties
|
|
const itemTitle = computed(() => {
|
|
return props.item?.name || 'Document';
|
|
});
|
|
|
|
const itemFileName = computed(() => {
|
|
if (props.item?.type === 'file') {
|
|
return props.item.name;
|
|
}
|
|
return '';
|
|
});
|
|
|
|
// Methods
|
|
const closeDialog = () => {
|
|
// Reset form
|
|
selectedAccessType.value = 'view';
|
|
accessDuration.value = '7 days';
|
|
justification.value = '';
|
|
formError.value = '';
|
|
|
|
emit('close');
|
|
};
|
|
|
|
const submitRequest = async () => {
|
|
// Validate form
|
|
if (!selectedAccessType.value) {
|
|
formError.value = 'Please select an access type';
|
|
return;
|
|
}
|
|
|
|
if (!justification.value.trim()) {
|
|
formError.value = 'Please provide a justification for your request';
|
|
return;
|
|
}
|
|
|
|
isSubmitting.value = true;
|
|
formError.value = '';
|
|
|
|
try {
|
|
// Submit the request to the store
|
|
const request = await dmsStore.requestAccess(
|
|
props.item.id,
|
|
selectedAccessType.value,
|
|
justification.value,
|
|
accessDuration.value
|
|
);
|
|
|
|
// Emit success event
|
|
emit('submit', request);
|
|
|
|
// Close the dialog (this will also reset the form)
|
|
closeDialog();
|
|
} catch (error) {
|
|
formError.value = 'Failed to submit access request. Please try again.';
|
|
console.error('Access request error:', error);
|
|
} finally {
|
|
isSubmitting.value = false;
|
|
}
|
|
};
|
|
</script>
|
|
|
|
<template>
|
|
<rs-modal
|
|
:visible="visible"
|
|
@close="closeDialog"
|
|
title="Request Document Access"
|
|
size="md"
|
|
>
|
|
<template #body>
|
|
<div class="p-6">
|
|
<!-- Document Information Section -->
|
|
<div class="mb-6">
|
|
<div class="bg-blue-50 dark:bg-blue-900/10 rounded-lg p-4 border border-blue-200 dark:border-blue-800">
|
|
<h3 class="text-sm font-medium text-blue-900 dark:text-blue-100 mb-2">Document Information</h3>
|
|
<div class="space-y-1">
|
|
<div class="flex">
|
|
<span class="text-sm font-medium text-gray-700 dark:text-gray-300 w-12">Title:</span>
|
|
<span class="text-sm text-gray-900 dark:text-gray-100">{{ itemTitle }}</span>
|
|
</div>
|
|
<div class="flex">
|
|
<span class="text-sm font-medium text-gray-700 dark:text-gray-300 w-12">File:</span>
|
|
<span class="text-sm text-gray-600 dark:text-gray-400">{{ itemFileName }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Form error -->
|
|
<div v-if="formError" class="mb-4 p-3 bg-red-50 border border-red-200 text-red-800 rounded-md text-sm">
|
|
{{ formError }}
|
|
</div>
|
|
|
|
<!-- Access Type Section -->
|
|
<div class="mb-6">
|
|
<h3 class="text-sm font-medium text-gray-900 dark:text-gray-100 mb-3">Access Type</h3>
|
|
<div class="grid grid-cols-2 gap-3">
|
|
<div
|
|
v-for="accessType in accessTypes"
|
|
:key="accessType.id"
|
|
class="relative"
|
|
>
|
|
<label
|
|
:for="accessType.id"
|
|
class="flex items-start p-3 border rounded-lg cursor-pointer transition-colors"
|
|
:class="selectedAccessType === accessType.id
|
|
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20'
|
|
: 'border-gray-200 dark:border-gray-700 hover:bg-gray-50 dark:hover:bg-gray-800'"
|
|
>
|
|
<div class="flex items-center h-5">
|
|
<input
|
|
:id="accessType.id"
|
|
v-model="selectedAccessType"
|
|
:value="accessType.id"
|
|
type="radio"
|
|
class="w-4 h-4 text-blue-600 border-gray-300 focus:ring-blue-500"
|
|
/>
|
|
</div>
|
|
<div class="ml-3">
|
|
<div class="text-sm font-medium text-gray-900 dark:text-gray-100">
|
|
{{ accessType.label }}
|
|
</div>
|
|
<div class="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
|
{{ accessType.description }}
|
|
</div>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Access Duration Section -->
|
|
<div class="mb-6">
|
|
<label class="block text-sm font-medium text-gray-900 dark:text-gray-100 mb-2">Access Duration</label>
|
|
<select
|
|
v-model="accessDuration"
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
|
|
>
|
|
<option v-for="duration in durationOptions" :key="duration" :value="duration">
|
|
{{ duration }}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
|
|
<!-- Justification Section -->
|
|
<div class="mb-6">
|
|
<label class="block text-sm font-medium text-gray-900 dark:text-gray-100 mb-2">
|
|
Justification
|
|
<span class="text-red-500">*</span>
|
|
</label>
|
|
<textarea
|
|
v-model="justification"
|
|
rows="4"
|
|
placeholder="Please explain why you need access to this document..."
|
|
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-lg bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder-gray-500 dark:placeholder-gray-400 focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none"
|
|
></textarea>
|
|
</div>
|
|
|
|
<!-- Footer Note -->
|
|
<p class="text-xs text-gray-500 dark:text-gray-400 mb-6">
|
|
Your request will be reviewed by the document owner or administrator.
|
|
</p>
|
|
</div>
|
|
</template>
|
|
|
|
<template #footer>
|
|
<div class="flex justify-end gap-3 px-6 py-4 bg-gray-50 dark:bg-gray-800">
|
|
<rs-button
|
|
@click="closeDialog"
|
|
:disabled="isSubmitting"
|
|
variant="secondary-outline"
|
|
size="sm"
|
|
>
|
|
Cancel
|
|
</rs-button>
|
|
<rs-button
|
|
@click="submitRequest"
|
|
:disabled="isSubmitting"
|
|
variant="primary"
|
|
size="sm"
|
|
>
|
|
<svg v-if="isSubmitting" class="animate-spin -ml-1 mr-2 h-4 w-4 text-white" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
|
|
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
|
|
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
|
|
</svg>
|
|
Submit Request
|
|
</rs-button>
|
|
</div>
|
|
</template>
|
|
</rs-modal>
|
|
</template> |