99 lines
3.3 KiB
Vue
99 lines
3.3 KiB
Vue
<script setup>
|
|
import { computed } from "vue";
|
|
import { CalendarDays, ChevronRight, MapPin, Phone, Wallet } from "lucide-vue-next";
|
|
import { fmtDateDMY } from "@/Utilities/functions";
|
|
import {
|
|
Card,
|
|
CardContent,
|
|
CardDescription,
|
|
CardFooter,
|
|
CardHeader,
|
|
CardTitle,
|
|
} from "@/Components/ui/card";
|
|
import { Badge } from "@/Components/ui/badge";
|
|
import { Separator } from "@/Components/ui/separator";
|
|
import { cn } from "@/lib/utils";
|
|
|
|
const props = defineProps({
|
|
job: { type: Object, required: true },
|
|
href: { type: String, default: null },
|
|
accentClass: { type: String, default: "border-blue-500" },
|
|
showLastActivity: { type: Boolean, default: false },
|
|
});
|
|
|
|
const person = computed(() => props.job.contract?.client_case?.person);
|
|
const clientName = computed(
|
|
() => props.job.contract?.client_case?.client?.person?.full_name
|
|
);
|
|
const address = computed(() => person.value?.address?.address);
|
|
const phone = computed(() => person.value?.phones?.[0]?.nu);
|
|
const balance = computed(() => props.job.contract?.account?.balance_amount);
|
|
|
|
function formatAmount(val) {
|
|
if (val === null || val === undefined) return "0,00";
|
|
const num = typeof val === "number" ? val : parseFloat(val);
|
|
if (Number.isNaN(num)) return String(val);
|
|
return num.toLocaleString("sl-SI", {
|
|
minimumFractionDigits: 2,
|
|
maximumFractionDigits: 2,
|
|
});
|
|
}
|
|
|
|
const dateLabel = computed(() =>
|
|
props.showLastActivity && props.job.last_activity
|
|
? fmtDateDMY(props.job.last_activity)
|
|
: fmtDateDMY(props.job.assigned_at)
|
|
);
|
|
</script>
|
|
|
|
<template>
|
|
<component
|
|
:is="href ? 'a' : 'div'"
|
|
:href="href ?? undefined"
|
|
:class="
|
|
href ? 'block active:scale-[0.99] transition-transform duration-100' : 'opacity-60'
|
|
"
|
|
>
|
|
<Card class="py-0! overflow-hidden gap-2">
|
|
<CardHeader :class="cn('p-3 py-2! border-b-2', accentClass)">
|
|
<CardTitle class="flex justify-between items-center">
|
|
<span class="font-bold">{{ person?.full_name || "—" }}</span>
|
|
|
|
<Badge
|
|
v-if="balance != null"
|
|
class="bg-error-100 text-error-500 text-sm font-bold flex gap-1 items-center"
|
|
>
|
|
<Wallet :size="14" />
|
|
<span>{{ formatAmount(balance) }} €</span>
|
|
</Badge>
|
|
</CardTitle>
|
|
<CardDescription class="flex gap-1 py-2">
|
|
<Badge class="font-bold" variant="secondary">{{
|
|
job.contract?.reference || job.contract?.uuid || "—"
|
|
}}</Badge>
|
|
<Badge v-if="clientName">{{ clientName }}</Badge>
|
|
</CardDescription>
|
|
</CardHeader>
|
|
<CardContent class="p-3 flex flex-row items-center justify-between gap-2">
|
|
<div class="flex flex-auto items-center-safe gap-2">
|
|
<p v-if="address" class="flex items-center gap-1 text-sm border p-1 rounded-md">
|
|
<MapPin :size="14" class="text-gray-500" />
|
|
{{ address }}
|
|
</p>
|
|
<p v-if="phone" class="flex items-center gap-2 text-sm border p-1 rounded-md">
|
|
<Phone :size="14" class="text-gray-500" />
|
|
{{ phone }}
|
|
</p>
|
|
</div>
|
|
<ChevronRight />
|
|
</CardContent>
|
|
<CardFooter class="bg-gray-50/60 border-t p-3 pt-3!">
|
|
<div class="flex items-center gap-1 text-sm text-gray-500">
|
|
<CalendarDays :size="12" />
|
|
<span>{{ dateLabel }}</span>
|
|
</div>
|
|
</CardFooter>
|
|
</Card>
|
|
</component>
|
|
</template>
|