395 lines
14 KiB
Vue
395 lines
14 KiB
Vue
<script setup>
|
||
import AdminLayout from "@/Layouts/AdminLayout.vue";
|
||
import { Head, Link, useForm, router } from "@inertiajs/vue3";
|
||
import { ref, computed, watch } from "vue";
|
||
import { ArrowLeftIcon, SaveIcon, MessageSquareIcon, SendIcon } from "lucide-vue-next";
|
||
import {
|
||
Card,
|
||
CardContent,
|
||
CardDescription,
|
||
CardHeader,
|
||
CardTitle,
|
||
} from "@/Components/ui/card";
|
||
import { Button } from "@/Components/ui/button";
|
||
import { Input } from "@/Components/ui/input";
|
||
import { Label } from "@/Components/ui/label";
|
||
import { Textarea } from "@/Components/ui/textarea";
|
||
import { Switch } from "@/Components/ui/switch";
|
||
import {
|
||
Select,
|
||
SelectContent,
|
||
SelectItem,
|
||
SelectTrigger,
|
||
SelectValue,
|
||
} from "@/Components/ui/select";
|
||
import { Separator } from "@/Components/ui/separator";
|
||
|
||
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'" />
|
||
|
||
<Card class="mb-6">
|
||
<CardHeader>
|
||
<div class="flex items-start justify-between">
|
||
<div class="flex items-start gap-3">
|
||
<div
|
||
class="inline-flex items-center justify-center h-10 w-10 rounded-lg bg-primary/10 text-primary"
|
||
>
|
||
<MessageSquareIcon class="h-5 w-5" />
|
||
</div>
|
||
<div>
|
||
<CardTitle>{{
|
||
props.template ? "Uredi SMS predlogo" : "Nova SMS predloga"
|
||
}}</CardTitle>
|
||
<CardDescription v-if="props.template"
|
||
>#{{ props.template.id }}</CardDescription
|
||
>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center gap-2">
|
||
<Button variant="outline" size="sm" as-child>
|
||
<Link :href="route('admin.sms-templates.index')">
|
||
<ArrowLeftIcon class="h-4 w-4 mr-2" />
|
||
Nazaj
|
||
</Link>
|
||
</Button>
|
||
<Button size="sm" @click="submit" :disabled="form.processing">
|
||
<SaveIcon class="h-4 w-4 mr-2" />
|
||
Shrani
|
||
</Button>
|
||
</div>
|
||
</div>
|
||
</CardHeader>
|
||
</Card>
|
||
|
||
<div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||
<Card class="lg:col-span-2">
|
||
<CardHeader>
|
||
<CardTitle class="text-base">Nastavitve predloge</CardTitle>
|
||
</CardHeader>
|
||
<CardContent class="space-y-4">
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<div class="space-y-2">
|
||
<Label for="name">Ime</Label>
|
||
<Input id="name" v-model="form.name" type="text" />
|
||
</div>
|
||
<div class="space-y-2">
|
||
<Label for="slug">Slug</Label>
|
||
<Input
|
||
id="slug"
|
||
v-model="form.slug"
|
||
type="text"
|
||
placeholder="npr. payment_reminder"
|
||
/>
|
||
</div>
|
||
<div class="md:col-span-2 space-y-2">
|
||
<Label for="content">Vsebina</Label>
|
||
<Textarea
|
||
id="content"
|
||
v-model="form.content"
|
||
rows="8"
|
||
placeholder="Pozdravljen {{ person.first_name }}, ..."
|
||
/>
|
||
<p class="text-xs text-muted-foreground">
|
||
Uporabite placeholderje npr.
|
||
<code class="bg-muted px-1 py-0.5 rounded">{first_name}</code> ali
|
||
<code class="bg-muted px-1 py-0.5 rounded" v-pre>{{
|
||
person.first_name
|
||
}}</code>
|
||
– ob pošiljanju se vrednosti nadomestijo.
|
||
</p>
|
||
</div>
|
||
<div class="md:col-span-2 space-y-2">
|
||
<div class="flex items-center gap-2">
|
||
<Switch
|
||
id="allow-custom"
|
||
:default-value="form.allow_custom_body"
|
||
@update:model-value="(val) => (form.allow_custom_body = val)"
|
||
/>
|
||
<Label for="allow-custom" class="font-normal cursor-pointer"
|
||
>Dovoli lastno besedilo</Label
|
||
>
|
||
</div>
|
||
<p class="text-xs text-muted-foreground">
|
||
Če je omogočeno, lahko pošiljatelj namesto vsebine predloge napiše
|
||
poljubno besedilo.
|
||
</p>
|
||
</div>
|
||
<div class="space-y-2">
|
||
<Label for="profile">Privzet profil</Label>
|
||
<Select v-model="form.default_profile_id">
|
||
<SelectTrigger id="profile">
|
||
<SelectValue placeholder="Izberi profil" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem :value="null">—</SelectItem>
|
||
<SelectItem v-for="p in props.profiles" :key="p.id" :value="p.id">{{
|
||
p.name
|
||
}}</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div class="space-y-2">
|
||
<Label for="sender">Privzet sender</Label>
|
||
<Select
|
||
v-model="form.default_sender_id"
|
||
:disabled="!form.default_profile_id"
|
||
>
|
||
<SelectTrigger id="sender">
|
||
<SelectValue placeholder="Izberi sender" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem :value="null">—</SelectItem>
|
||
<SelectItem
|
||
v-for="s in currentSendersForProfile(form.default_profile_id)"
|
||
:key="s.id"
|
||
:value="s.id"
|
||
>
|
||
{{ s.sname }}
|
||
</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div class="space-y-2">
|
||
<div class="flex items-center gap-2">
|
||
<Switch
|
||
id="active"
|
||
:default-value="form.is_active"
|
||
@update:model-value="(val) => (form.is_active = val)"
|
||
/>
|
||
<Label for="active" class="font-normal cursor-pointer">Aktivno</Label>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<Separator />
|
||
|
||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||
<div class="space-y-2">
|
||
<Label for="action">Akcija po pošiljanju</Label>
|
||
<Select v-model="form.action_id">
|
||
<SelectTrigger id="action">
|
||
<SelectValue placeholder="Brez" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem :value="null">Brez</SelectItem>
|
||
<SelectItem v-for="a in props.actions" :key="a.id" :value="a.id">{{
|
||
a.name
|
||
}}</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div class="space-y-2">
|
||
<Label for="decision">Odločitev</Label>
|
||
<Select v-model="form.decision_id" :disabled="!form.action_id">
|
||
<SelectTrigger id="decision">
|
||
<SelectValue placeholder="Brez" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem :value="null">Brez</SelectItem>
|
||
<SelectItem
|
||
v-for="d in props.actions.find((x) => x.id === form.action_id)
|
||
?.decisions || []"
|
||
:key="d.id"
|
||
:value="d.id"
|
||
>{{ d.name }}</SelectItem
|
||
>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
|
||
<Card>
|
||
<CardHeader>
|
||
<CardTitle class="text-base">Testno pošiljanje</CardTitle>
|
||
<CardDescription>Pošljite testno SMS sporočilo</CardDescription>
|
||
</CardHeader>
|
||
<CardContent class="space-y-4">
|
||
<div class="space-y-4">
|
||
<div class="space-y-2">
|
||
<Label for="test-to">Prejemnik (E.164)</Label>
|
||
<Input
|
||
id="test-to"
|
||
v-model="testForm.to"
|
||
type="text"
|
||
placeholder="+386..."
|
||
/>
|
||
</div>
|
||
<div class="space-y-2">
|
||
<Label for="test-country">Državna koda</Label>
|
||
<Input
|
||
id="test-country"
|
||
v-model="testForm.country_code"
|
||
type="text"
|
||
placeholder="SI"
|
||
/>
|
||
</div>
|
||
<div class="space-y-2">
|
||
<Label for="test-profile">Profil</Label>
|
||
<Select v-model="testForm.profile_id">
|
||
<SelectTrigger id="test-profile">
|
||
<SelectValue placeholder="Privzeti" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem :value="null">Privzeti</SelectItem>
|
||
<SelectItem v-for="p in props.profiles" :key="p.id" :value="p.id">{{
|
||
p.name
|
||
}}</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div class="space-y-2">
|
||
<Label for="test-sender">Sender</Label>
|
||
<Select v-model="testForm.sender_id" :disabled="!testForm.profile_id">
|
||
<SelectTrigger id="test-sender">
|
||
<SelectValue placeholder="Privzeti" />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem :value="null">Privzeti</SelectItem>
|
||
<SelectItem
|
||
v-for="s in currentSendersForProfile(testForm.profile_id)"
|
||
:key="s.id"
|
||
:value="s.id"
|
||
>{{ s.sname }}</SelectItem
|
||
>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div class="space-y-2">
|
||
<Label for="test-delivery">Dostavna poročila</Label>
|
||
<Select v-model="testForm.delivery_report">
|
||
<SelectTrigger id="test-delivery">
|
||
<SelectValue />
|
||
</SelectTrigger>
|
||
<SelectContent>
|
||
<SelectItem :value="true">Da</SelectItem>
|
||
<SelectItem :value="false">Ne</SelectItem>
|
||
</SelectContent>
|
||
</Select>
|
||
</div>
|
||
<div v-if="form.allow_custom_body" class="space-y-2">
|
||
<Label for="test-custom">Lastno besedilo (opcijsko)</Label>
|
||
<Textarea
|
||
id="test-custom"
|
||
v-model="testForm.custom_content"
|
||
rows="4"
|
||
placeholder="Če je izpolnjeno, bo namesto predloge poslano to besedilo."
|
||
/>
|
||
</div>
|
||
</div>
|
||
<div class="flex items-center justify-end">
|
||
<Button
|
||
@click="submitTest"
|
||
:disabled="testForm.processing || !props.template"
|
||
>
|
||
<SendIcon class="h-4 w-4 mr-2" />
|
||
Pošlji test
|
||
</Button>
|
||
</div>
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
</AdminLayout>
|
||
</template>
|
||
|
||
<style scoped></style>
|