Teren-app/resources/js/Pages/Admin/SmsTemplates/Edit.vue
2026-01-05 18:27:35 +01:00

395 lines
14 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<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>