Admin panel updated with shadcn-vue components
This commit is contained in:
@@ -2,6 +2,27 @@
|
||||
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 },
|
||||
@@ -104,160 +125,270 @@ async function submitTest() {
|
||||
<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>
|
||||
<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">
|
||||
<!-- 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.
|
||||
<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>
|
||||
<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..." />
|
||||
<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>
|
||||
<div>
|
||||
<label class="label">Državna koda</label>
|
||||
<input v-model="testForm.country_code" type="text" class="input" placeholder="SI" />
|
||||
</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>
|
||||
<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 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>
|
||||
<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>
|
||||
</CardContent>
|
||||
</Card>
|
||||
</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>
|
||||
<style scoped></style>
|
||||
|
||||
@@ -1,10 +1,25 @@
|
||||
<script setup>
|
||||
import AdminLayout from "@/Layouts/AdminLayout.vue";
|
||||
import DialogModal from "@/Components/DialogModal.vue";
|
||||
import { Head, useForm, Link, router } from "@inertiajs/vue3";
|
||||
import { computed, ref } from "vue";
|
||||
import { FontAwesomeIcon } from "@fortawesome/vue-fontawesome";
|
||||
import { faPlus, faPen, faTrash, faPaperPlane } from "@fortawesome/free-solid-svg-icons";
|
||||
import { PlusIcon, PencilIcon, Trash2Icon, SendIcon, MessageSquareIcon, MoreVerticalIcon } 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 { Badge } from '@/Components/ui/badge';
|
||||
import { Switch } from '@/Components/ui/switch';
|
||||
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/Components/ui/table';
|
||||
import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle } from '@/Components/ui/dialog';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/Components/ui/select';
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/Components/ui/dropdown-menu';
|
||||
|
||||
const props = defineProps({
|
||||
initialTemplates: { type: Array, default: () => [] },
|
||||
@@ -159,174 +174,173 @@ function currentSendersForTest() {
|
||||
<template>
|
||||
<AdminLayout title="SMS predloge">
|
||||
<Head title="SMS predloge" />
|
||||
<div class="flex items-center justify-between mb-6">
|
||||
<h1 class="text-xl font-semibold text-gray-800">SMS predloge</h1>
|
||||
<Link
|
||||
:href="route('admin.sms-templates.create')"
|
||||
class="inline-flex items-center gap-2 px-4 py-2 rounded-md bg-indigo-600 text-white text-sm font-medium hover:bg-indigo-500 shadow"
|
||||
>
|
||||
<FontAwesomeIcon :icon="faPlus" class="w-4 h-4" /> Nova predloga
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border bg-white overflow-hidden shadow-sm">
|
||||
<table class="w-full text-sm">
|
||||
<thead class="bg-gray-50 text-gray-600 text-xs uppercase tracking-wider">
|
||||
<tr>
|
||||
<th class="px-3 py-2 text-left">Ime</th>
|
||||
<th class="px-3 py-2 text-left">Slug</th>
|
||||
<th class="px-3 py-2 text-left">Privzet profil/sender</th>
|
||||
<th class="px-3 py-2">Aktivno</th>
|
||||
<th class="px-3 py-2">Akcije</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr
|
||||
v-for="t in templates"
|
||||
:key="t.id"
|
||||
class="border-t last:border-b hover:bg-gray-50"
|
||||
>
|
||||
<td class="px-3 py-2 font-medium text-gray-800">{{ t.name }}</td>
|
||||
<td class="px-3 py-2 text-gray-600">{{ t.slug }}</td>
|
||||
<td class="px-3 py-2 text-gray-600">
|
||||
<span>{{ profilesById[t.default_profile_id]?.name || "—" }}</span>
|
||||
<span v-if="t.default_sender_id">
|
||||
/ {{ sendersById[t.default_sender_id]?.sname }}</span
|
||||
>
|
||||
</td>
|
||||
<td class="px-3 py-2 text-center">
|
||||
<span :class="t.is_active ? 'text-emerald-600' : 'text-rose-600'">{{
|
||||
t.is_active ? "Da" : "Ne"
|
||||
}}</span>
|
||||
</td>
|
||||
<td class="px-3 py-2 flex items-center gap-2">
|
||||
<Link
|
||||
:href="route('admin.sms-templates.edit', t.id)"
|
||||
class="inline-flex items-center gap-1 text-xs px-2 py-1 rounded border text-indigo-700 border-indigo-300 bg-indigo-50 hover:bg-indigo-100"
|
||||
>
|
||||
<FontAwesomeIcon :icon="faPen" class="w-3.5 h-3.5" /> Uredi
|
||||
</Link>
|
||||
<button
|
||||
@click="openTest(t)"
|
||||
class="inline-flex items-center gap-1 text-xs px-2 py-1 rounded border text-emerald-700 border-emerald-300 bg-emerald-50 hover:bg-emerald-100"
|
||||
>
|
||||
<FontAwesomeIcon :icon="faPaperPlane" class="w-3.5 h-3.5" /> Test
|
||||
</button>
|
||||
<button
|
||||
@click="destroyTemplate(t)"
|
||||
class="inline-flex items-center gap-1 text-xs px-2 py-1 rounded border text-rose-700 border-rose-300 bg-rose-50 hover:bg-rose-100"
|
||||
>
|
||||
<FontAwesomeIcon :icon="faTrash" class="w-3.5 h-3.5" /> Izbriši
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<Card>
|
||||
<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>SMS predloge</CardTitle>
|
||||
<CardDescription>Upravljajte predloge za SMS sporočila</CardDescription>
|
||||
</div>
|
||||
</div>
|
||||
<Button as-child>
|
||||
<Link :href="route('admin.sms-templates.create')">
|
||||
<PlusIcon class="h-4 w-4 mr-2" />
|
||||
Nova predloga
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
|
||||
<!-- Edit/Create now handled on dedicated page -->
|
||||
<Table>
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Ime</TableHead>
|
||||
<TableHead>Slug</TableHead>
|
||||
<TableHead>Privzet profil/sender</TableHead>
|
||||
<TableHead class="text-center">Aktivno</TableHead>
|
||||
<TableHead class="text-right">Akcije</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow v-for="t in templates" :key="t.id">
|
||||
<TableCell class="font-medium">{{ t.name }}</TableCell>
|
||||
<TableCell>
|
||||
<Badge variant="outline">{{ t.slug }}</Badge>
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<div class="text-sm">
|
||||
<span>{{ profilesById[t.default_profile_id]?.name || "—" }}</span>
|
||||
<span v-if="t.default_sender_id" class="text-muted-foreground">
|
||||
/ {{ sendersById[t.default_sender_id]?.sname }}
|
||||
</span>
|
||||
</div>
|
||||
</TableCell>
|
||||
<TableCell class="text-center">
|
||||
<Badge v-if="t.is_active" variant="default" class="bg-green-100 text-green-800 hover:bg-green-100">Da</Badge>
|
||||
<Badge v-else variant="secondary">Ne</Badge>
|
||||
</TableCell>
|
||||
<TableCell class="text-right">
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger as-child>
|
||||
<Button variant="ghost" size="sm">
|
||||
<MoreVerticalIcon class="h-4 w-4" />
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end">
|
||||
<DropdownMenuLabel>Akcije</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem as-child>
|
||||
<Link :href="route('admin.sms-templates.edit', t.id)">
|
||||
<PencilIcon class="h-4 w-4 mr-2" />
|
||||
Uredi
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem @click="openTest(t)">
|
||||
<SendIcon class="h-4 w-4 mr-2" />
|
||||
Testno pošiljanje
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem @click="destroyTemplate(t)" class="text-destructive">
|
||||
<Trash2Icon class="h-4 w-4 mr-2" />
|
||||
Izbriši
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</CardContent>
|
||||
</Card>
|
||||
|
||||
<!-- Test Send Modal -->
|
||||
<DialogModal :show="testOpen" max-width="2xl" @close="() => (testOpen = false)">
|
||||
<template #title> Testno pošiljanje </template>
|
||||
<template #content>
|
||||
<Dialog :open="testOpen" @update:open="(val) => testOpen = val">
|
||||
<DialogContent class="max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Testno pošiljanje</DialogTitle>
|
||||
<DialogDescription>Pošljite testno SMS sporočilo</DialogDescription>
|
||||
</DialogHeader>
|
||||
<div class="space-y-4">
|
||||
<div class="grid gap-4 grid-cols-2">
|
||||
<div>
|
||||
<label class="label">Prejemnik (E.164)</label>
|
||||
<input
|
||||
<div class="space-y-2">
|
||||
<Label for="test-to">Prejemnik (E.164)</Label>
|
||||
<Input
|
||||
id="test-to"
|
||||
v-model="testForm.to"
|
||||
type="text"
|
||||
class="input"
|
||||
placeholder="+386..."
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<label class="label">Državna koda</label>
|
||||
<input
|
||||
<div class="space-y-2">
|
||||
<Label for="test-country">Državna koda</Label>
|
||||
<Input
|
||||
id="test-country"
|
||||
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 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>
|
||||
<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 currentSendersForTest()" :key="s.id" :value="s.id">
|
||||
{{ s.sname }}
|
||||
</option>
|
||||
</select>
|
||||
<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 currentSendersForTest()" :key="s.id" :value="s.id">
|
||||
{{ s.sname }}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</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 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>
|
||||
<!-- Result details removed in favor of flash messages after redirect -->
|
||||
</div>
|
||||
</template>
|
||||
<template #footer>
|
||||
<button
|
||||
type="button"
|
||||
@click="() => (testOpen = false)"
|
||||
class="px-4 py-2 text-sm rounded-md border bg-white hover:bg-gray-50"
|
||||
>
|
||||
Zapri
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@click="submitTest"
|
||||
:disabled="testForm.processing || !testTarget"
|
||||
class="px-4 py-2 text-sm rounded-md bg-emerald-600 text-white hover:bg-emerald-500 disabled:opacity-50"
|
||||
>
|
||||
<FontAwesomeIcon :icon="faPaperPlane" class="w-3.5 h-3.5 mr-1" /> Pošlji test
|
||||
</button>
|
||||
</template>
|
||||
</DialogModal>
|
||||
<DialogFooter>
|
||||
<Button variant="outline" @click="() => testOpen = false">Zapri</Button>
|
||||
<Button
|
||||
@click="submitTest"
|
||||
:disabled="testForm.processing || !testTarget"
|
||||
>
|
||||
<SendIcon class="h-4 w-4 mr-2" />
|
||||
Pošlji test
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</AdminLayout>
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
.input {
|
||||
width: 100%;
|
||||
border-radius: 0.375rem;
|
||||
border: 1px solid var(--tw-color-gray-300, #d1d5db);
|
||||
padding: 0.5rem 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
line-height: 1.25rem;
|
||||
}
|
||||
.input:focus {
|
||||
outline: 2px solid transparent;
|
||||
outline-offset: 2px;
|
||||
--tw-ring-color: #6366f1;
|
||||
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>
|
||||
|
||||
Reference in New Issue
Block a user