170 lines
6.6 KiB
Vue
170 lines
6.6 KiB
Vue
<script setup>
|
|
import AppLayout from '@/Layouts/AppLayout.vue';
|
|
import { ref } from 'vue';
|
|
import { useForm } from '@inertiajs/vue3';
|
|
import Multiselect from 'vue-multiselect';
|
|
import { computed, watch } from 'vue';
|
|
|
|
const props = defineProps({
|
|
clients: Array,
|
|
segments: Array,
|
|
decisions: Array,
|
|
actions: Array,
|
|
});
|
|
|
|
const form = useForm({
|
|
name: '',
|
|
description: '',
|
|
source_type: 'csv',
|
|
default_record_type: '',
|
|
is_active: true,
|
|
client_uuid: null,
|
|
entities: [],
|
|
meta: {
|
|
segment_id: null,
|
|
decision_id: null,
|
|
action_id: null,
|
|
delimiter: '',
|
|
},
|
|
});
|
|
|
|
const decisionsForSelectedAction = computed(() => {
|
|
const act = (props.actions || []).find(a => a.id === form.meta.action_id);
|
|
return act?.decisions || [];
|
|
});
|
|
|
|
watch(() => form.meta.action_id, () => {
|
|
// Clear decision when action changes to enforce valid pair
|
|
form.meta.decision_id = null;
|
|
});
|
|
|
|
function submit() {
|
|
form.post(route('importTemplates.store'), {
|
|
onSuccess: () => {
|
|
// You can redirect or show a success message here
|
|
},
|
|
});
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<AppLayout title="Create Import Template">
|
|
<template #header>
|
|
<h2 class="font-semibold text-xl text-gray-800 leading-tight">Create Import Template</h2>
|
|
</template>
|
|
|
|
<div class="py-6">
|
|
<div class="max-w-3xl mx-auto sm:px-6 lg:px-8">
|
|
<div class="bg-white shadow sm:rounded-lg p-6 space-y-6">
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Client (optional)</label>
|
|
<Multiselect
|
|
v-model="form.client_uuid"
|
|
:options="props.clients || []"
|
|
:reduce="c => c.uuid"
|
|
track-by="uuid"
|
|
label="name"
|
|
placeholder="Global (no client)"
|
|
:searchable="true"
|
|
:allow-empty="true"
|
|
class="mt-1"
|
|
/>
|
|
<p class="text-xs text-gray-500 mt-1">Leave empty to make this template global (visible to all clients).</p>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Entities (tables)</label>
|
|
<Multiselect
|
|
v-model="form.entities"
|
|
:options="[
|
|
{ value: 'person', label: 'Person' },
|
|
{ value: 'person_addresses', label: 'Person Addresses' },
|
|
{ value: 'person_phones', label: 'Person Phones' },
|
|
{ value: 'emails', label: 'Emails' },
|
|
{ value: 'accounts', label: 'Accounts' },
|
|
{ value: 'contracts', label: 'Contracts' },
|
|
]"
|
|
:multiple="true"
|
|
track-by="value"
|
|
label="label"
|
|
:reduce="o => o.value"
|
|
placeholder="Select one or more entities"
|
|
:searchable="false"
|
|
class="mt-1"
|
|
/>
|
|
<p class="text-xs text-gray-500 mt-1">Choose which tables this template targets. You can still define per-column mappings later.</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Defaults: Segment / Decision / Action -->
|
|
<div class="grid grid-cols-1 sm:grid-cols-3 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Default Segment</label>
|
|
<select v-model="form.meta.segment_id" class="mt-1 block w-full border rounded p-2">
|
|
<option :value="null">(none)</option>
|
|
<option v-for="s in (props.segments || [])" :key="s.id" :value="s.id">{{ s.name }}</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Default Decision</label>
|
|
<select v-model="form.meta.decision_id" class="mt-1 block w-full border rounded p-2" :disabled="!form.meta.action_id">
|
|
<option :value="null">(none)</option>
|
|
<option v-for="d in decisionsForSelectedAction" :key="d.id" :value="d.id">{{ d.name }}</option>
|
|
</select>
|
|
<p v-if="!form.meta.action_id" class="text-xs text-gray-500 mt-1">Select an Action to see its Decisions.</p>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Default Action (for Activity)</label>
|
|
<select v-model="form.meta.action_id" class="mt-1 block w-full border rounded p-2">
|
|
<option :value="null">(none)</option>
|
|
<option v-for="a in (props.actions || [])" :key="a.id" :value="a.id">{{ a.name }}</option>
|
|
</select>
|
|
</div>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Name</label>
|
|
<input v-model="form.name" type="text" class="mt-1 block w-full border rounded p-2" />
|
|
</div>
|
|
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Description</label>
|
|
<textarea v-model="form.description" class="mt-1 block w-full border rounded p-2" rows="3" />
|
|
</div>
|
|
|
|
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Source Type</label>
|
|
<select v-model="form.source_type" class="mt-1 block w-full border rounded p-2">
|
|
<option value="csv">CSV</option>
|
|
<option value="xml">XML</option>
|
|
<option value="xls">XLS</option>
|
|
<option value="xlsx">XLSX</option>
|
|
<option value="json">JSON</option>
|
|
</select>
|
|
</div>
|
|
<div>
|
|
<label class="block text-sm font-medium text-gray-700">Default Record Type (optional)</label>
|
|
<input v-model="form.default_record_type" type="text" class="mt-1 block w-full border rounded p-2" placeholder="e.g., account, person" />
|
|
</div>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-2">
|
|
<input id="is_active" v-model="form.is_active" type="checkbox" class="rounded" />
|
|
<label for="is_active" class="text-sm font-medium text-gray-700">Active</label>
|
|
</div>
|
|
|
|
<div class="pt-4">
|
|
<button @click.prevent="submit" class="px-4 py-2 bg-emerald-600 text-white rounded" :disabled="form.processing">
|
|
{{ form.processing ? 'Saving…' : 'Create Template' }}
|
|
</button>
|
|
</div>
|
|
|
|
<div v-if="form.errors && Object.keys(form.errors).length" class="text-sm text-red-600">
|
|
<div v-for="(msg, key) in form.errors" :key="key">{{ msg }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</AppLayout>
|
|
</template>
|