264 lines
9.7 KiB
Vue
264 lines
9.7 KiB
Vue
<script setup>
|
||
import AdminLayout from "@/Layouts/AdminLayout.vue";
|
||
import { Head, Link, useForm, router } from "@inertiajs/vue3";
|
||
import { ref, computed, watch } from "vue";
|
||
|
||
const props = defineProps({
|
||
template: { type: Object, default: null },
|
||
profiles: { type: Array, default: () => [] },
|
||
senders: { type: Array, default: () => [] },
|
||
actions: { type: Array, default: () => [] },
|
||
});
|
||
|
||
const form = useForm({
|
||
name: props.template?.name ?? "",
|
||
slug: props.template?.slug ?? "",
|
||
content: props.template?.content ?? "",
|
||
variables_json: props.template?.variables_json ?? {},
|
||
is_active: props.template?.is_active ?? true,
|
||
default_profile_id: props.template?.default_profile_id ?? null,
|
||
default_sender_id: props.template?.default_sender_id ?? null,
|
||
allow_custom_body: props.template?.allow_custom_body ?? false,
|
||
action_id: props.template?.action_id ?? null,
|
||
decision_id: props.template?.decision_id ?? null,
|
||
});
|
||
|
||
const sendersByProfile = computed(() => {
|
||
const map = {};
|
||
(props.senders || []).forEach((s) => {
|
||
if (!map[s.profile_id]) map[s.profile_id] = [];
|
||
map[s.profile_id].push(s);
|
||
});
|
||
return map;
|
||
});
|
||
|
||
function currentSendersForProfile(pid) {
|
||
if (!pid) return [];
|
||
return (sendersByProfile.value[pid] || []).filter((s) => s.active);
|
||
}
|
||
|
||
function submit() {
|
||
if (props.template?.id) {
|
||
form.put(route("admin.sms-templates.update", props.template.id));
|
||
} else {
|
||
form.post(route("admin.sms-templates.store"), {
|
||
onSuccess: (page) => {
|
||
// If backend redirected, nothing to do. If returned JSON, navigate to edit.
|
||
try {
|
||
const id = page?.props?.template?.id; // in case of redirect props
|
||
if (id) {
|
||
router.visit(route("admin.sms-templates.edit", id));
|
||
}
|
||
} catch {}
|
||
},
|
||
onFinish: () => {},
|
||
preserveScroll: true,
|
||
});
|
||
}
|
||
}
|
||
|
||
// Test send panel
|
||
const testForm = useForm({
|
||
to: "",
|
||
variables: {},
|
||
profile_id: props.template?.default_profile_id ?? null,
|
||
sender_id: props.template?.default_sender_id ?? null,
|
||
country_code: null,
|
||
delivery_report: true,
|
||
custom_content: "",
|
||
});
|
||
const testResult = ref(null);
|
||
|
||
watch(
|
||
() => testForm.profile_id,
|
||
() => {
|
||
// reset sender when profile changes
|
||
testForm.sender_id = null;
|
||
}
|
||
);
|
||
|
||
async function submitTest() {
|
||
if (!props.template?.id) {
|
||
alert("Najprej shranite predlogo.");
|
||
return;
|
||
}
|
||
const payload = {
|
||
to: testForm.to,
|
||
variables: testForm.variables || {},
|
||
profile_id: testForm.profile_id || null,
|
||
sender_id: testForm.sender_id || null,
|
||
country_code: testForm.country_code || null,
|
||
delivery_report: !!testForm.delivery_report,
|
||
custom_content: testForm.custom_content || null,
|
||
};
|
||
await router.post(route("admin.sms-templates.send-test", props.template.id), payload, {
|
||
preserveScroll: true,
|
||
onSuccess: () => {
|
||
testResult.value = null;
|
||
},
|
||
});
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<AdminLayout :title="props.template ? 'Uredi SMS predlogo' : 'Nova SMS predloga'">
|
||
<Head :title="props.template ? 'Uredi SMS predlogo' : 'Nova SMS predloga'" />
|
||
|
||
<div class="mb-4 flex items-center justify-between">
|
||
<div class="flex items-center gap-3">
|
||
<Link :href="route('admin.sms-templates.index')" class="text-sm text-indigo-600 hover:underline">← Nazaj na seznam</Link>
|
||
<div class="text-gray-700 text-sm" v-if="props.template">#{{ props.template.id }}</div>
|
||
</div>
|
||
<button
|
||
type="button"
|
||
@click="submit"
|
||
:disabled="form.processing"
|
||
class="px-4 py-2 text-sm rounded-md bg-indigo-600 text-white hover:bg-indigo-500 disabled:opacity-50"
|
||
>
|
||
Shrani
|
||
</button>
|
||
</div>
|
||
|
||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||
<!-- Form -->
|
||
<div class="lg:col-span-2 rounded-xl border bg-white/60 backdrop-blur-sm shadow-sm p-5 space-y-4">
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<div>
|
||
<label class="label">Ime</label>
|
||
<input v-model="form.name" type="text" class="input" />
|
||
</div>
|
||
<div>
|
||
<label class="label">Slug</label>
|
||
<input v-model="form.slug" type="text" class="input" placeholder="npr. payment_reminder" />
|
||
</div>
|
||
<div class="md:col-span-2">
|
||
<label class="label">Vsebina</label>
|
||
<textarea v-model="form.content" rows="8" class="input" placeholder="Pozdravljen {{ person.first_name }}, ..."></textarea>
|
||
<div class="text-[11px] text-gray-500 mt-1">
|
||
Uporabite placeholderje npr. <code>{first_name}</code> ali
|
||
<code v-pre>{{ person.first_name }}</code> – ob pošiljanju se vrednosti nadomestijo.
|
||
</div>
|
||
</div>
|
||
<div class="md:col-span-2">
|
||
<label class="label">Dovoli lastno besedilo</label>
|
||
<select v-model="form.allow_custom_body" class="input">
|
||
<option :value="true">Da</option>
|
||
<option :value="false">Ne</option>
|
||
</select>
|
||
<div class="text-[11px] text-gray-500 mt-1">Če je omogočeno, lahko pošiljatelj namesto vsebine predloge napiše poljubno besedilo.</div>
|
||
</div>
|
||
<div>
|
||
<label class="label">Privzet profil</label>
|
||
<select v-model="form.default_profile_id" class="input">
|
||
<option :value="null">—</option>
|
||
<option v-for="p in props.profiles" :key="p.id" :value="p.id">{{ p.name }}</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="label">Privzet sender</label>
|
||
<select v-model="form.default_sender_id" class="input" :disabled="!form.default_profile_id">
|
||
<option :value="null">—</option>
|
||
<option v-for="s in currentSendersForProfile(form.default_profile_id)" :key="s.id" :value="s.id">
|
||
{{ s.sname }}
|
||
</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="label">Aktivno</label>
|
||
<select v-model="form.is_active" class="input">
|
||
<option :value="true">Da</option>
|
||
<option :value="false">Ne</option>
|
||
</select>
|
||
</div>
|
||
<div class="md:col-span-2 grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<div>
|
||
<label class="label">Akcija po pošiljanju</label>
|
||
<select v-model="form.action_id" class="input">
|
||
<option :value="null">(brez)</option>
|
||
<option v-for="a in props.actions" :key="a.id" :value="a.id">{{ a.name }}</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="label">Odločitev</label>
|
||
<select v-model="form.decision_id" class="input" :disabled="!form.action_id">
|
||
<option :value="null">(brez)</option>
|
||
<option v-for="d in (props.actions.find(x => x.id === form.action_id)?.decisions || [])" :key="d.id" :value="d.id">{{ d.name }}</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Test send -->
|
||
<div class="rounded-xl border bg-white/60 backdrop-blur-sm shadow-sm p-5 space-y-4">
|
||
<div class="font-semibold text-gray-800">Testno pošiljanje</div>
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<div>
|
||
<label class="label">Prejemnik (E.164)</label>
|
||
<input v-model="testForm.to" type="text" class="input" placeholder="+386..." />
|
||
</div>
|
||
<div>
|
||
<label class="label">Državna koda</label>
|
||
<input v-model="testForm.country_code" type="text" class="input" placeholder="SI" />
|
||
</div>
|
||
<div>
|
||
<label class="label">Profil</label>
|
||
<select v-model="testForm.profile_id" class="input">
|
||
<option :value="null">(privzeti)</option>
|
||
<option v-for="p in props.profiles" :key="p.id" :value="p.id">{{ p.name }}</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="label">Sender</label>
|
||
<select v-model="testForm.sender_id" class="input" :disabled="!testForm.profile_id">
|
||
<option :value="null">(privzeti)</option>
|
||
<option v-for="s in currentSendersForProfile(testForm.profile_id)" :key="s.id" :value="s.id">{{ s.sname }}</option>
|
||
</select>
|
||
</div>
|
||
<div>
|
||
<label class="label">Dostavna poročila</label>
|
||
<select v-model="testForm.delivery_report" class="input">
|
||
<option :value="true">Da</option>
|
||
<option :value="false">Ne</option>
|
||
</select>
|
||
</div>
|
||
<div v-if="form.allow_custom_body" class="md:col-span-2">
|
||
<label class="label">Lastno besedilo (opcijsko)</label>
|
||
<textarea v-model="testForm.custom_content" rows="4" class="input" placeholder="Če je izpolnjeno, bo namesto predloge poslano to besedilo."></textarea>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center justify-end gap-2">
|
||
<button type="button" @click="submitTest" :disabled="testForm.processing || !props.template" class="px-3 py-2 text-sm rounded-md bg-emerald-600 text-white hover:bg-emerald-500 disabled:opacity-50">Pošlji test</button>
|
||
</div>
|
||
<!-- Result details removed in favor of flash messages after redirect -->
|
||
</div>
|
||
</div>
|
||
</AdminLayout>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.input {
|
||
width: 100%;
|
||
border-radius: 0.375rem;
|
||
border: 1px solid #d1d5db;
|
||
padding: 0.5rem 0.75rem;
|
||
font-size: 0.875rem;
|
||
line-height: 1.25rem;
|
||
}
|
||
.input:focus {
|
||
outline: 2px solid transparent;
|
||
outline-offset: 2px;
|
||
border-color: #6366f1;
|
||
box-shadow: 0 0 0 1px #6366f1;
|
||
}
|
||
.label {
|
||
display: block;
|
||
font-size: 0.65rem;
|
||
font-weight: 600;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
color: #6b7280;
|
||
margin-bottom: 0.25rem;
|
||
}
|
||
</style>
|