Files
isaaccladandCursor eaf6da5cdb
Deploy Ladill Care / deploy (push) Successful in 1m0s
Align Care header with other Ladill apps.
Add Afia and notifications to the top bar, remove the duplicate desktop page
title, wire notification and AI routes, and fix mobile nav notification links.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-29 12:53:34 +00:00

107 lines
7.0 KiB
PHP

@php
$afiaGreeting = "Hi, I'm Afia 👋 Ask me about patients, appointments, the queue, consultations, lab requests, prescriptions, or billing…";
$afiaSuggestions = [
'How do I register a new patient?',
'How does the patient queue work?',
'How do I start a consultation?',
'How do I request lab investigations?',
];
@endphp
{{-- Afia Ladill AI assistant slide-over. Opened via $dispatch('afia-open'). --}}
<div x-data="afia({
chatUrl: '{{ route('care.ai.chat') }}',
csrf: '{{ csrf_token() }}',
greeting: @js($afiaGreeting),
suggestions: @js($afiaSuggestions),
})" @afia-open.window="open = true; $nextTick(() => $refs.input && $refs.input.focus())">
<div x-show="open" x-cloak @click="close()" class="fixed inset-0 z-50 bg-slate-900/20"></div>
<section x-show="open" x-cloak
x-transition:enter="transition transform ease-out duration-200"
x-transition:enter-start="translate-x-full" x-transition:enter-end="translate-x-0"
x-transition:leave="transition transform ease-in duration-150"
x-transition:leave-start="translate-x-0" x-transition:leave-end="translate-x-full"
class="fixed inset-y-0 right-0 z-50 flex w-full max-w-md flex-col bg-white shadow-2xl">
<div class="flex items-center justify-between border-b border-slate-100 px-5 py-3.5">
<div class="flex items-center gap-2.5">
<span class="relative flex h-8 w-8 shrink-0 items-center justify-center">
<svg viewBox="0 0 36 36" class="h-8 w-8" aria-hidden="true">
<defs>
<radialGradient id="afia-orb" cx="40%" cy="35%" r="60%">
<stop offset="0%" stop-color="#a5b4fc"/>
<stop offset="50%" stop-color="#6366f1"/>
<stop offset="100%" stop-color="#3730a3"/>
</radialGradient>
</defs>
<circle cx="18" cy="18" r="14" fill="url(#afia-orb)">
<animate attributeName="r" values="14;14.8;14" dur="3s" repeatCount="indefinite"/>
</circle>
<circle cx="18" cy="18" r="11" fill="none" stroke="#c7d2fe" stroke-width=".6" opacity=".5">
<animate attributeName="r" values="11;12.5;11" dur="4s" repeatCount="indefinite"/>
<animate attributeName="opacity" values=".5;.15;.5" dur="4s" repeatCount="indefinite"/>
</circle>
<circle r="1.2" fill="#c7d2fe" opacity=".8">
<animateMotion dur="3s" repeatCount="indefinite" path="M18,8 A10,10 0 1,1 17.99,8" rotate="auto"/>
</circle>
</svg>
<span class="absolute -bottom-0.5 -right-0.5 h-2.5 w-2.5 rounded-full border-2 border-white bg-emerald-400"></span>
</span>
<div class="leading-tight">
<p class="text-sm font-semibold text-slate-900">Afia</p>
<p class="text-[11px] text-slate-400">Care assistant</p>
</div>
</div>
<div class="flex items-center gap-1">
<a href="{{ ladill_account_url('ai') }}"
class="rounded-lg px-2 py-1 text-[11px] font-medium text-slate-500 hover:bg-slate-100 hover:text-slate-700"
title="AI usage history on your Ladill account">History</a>
<button @click="close()" class="rounded-lg p-1.5 text-slate-400 hover:bg-slate-100 hover:text-slate-600">
<svg class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/></svg>
</button>
</div>
</div>
<div class="flex-1 overflow-y-auto px-4 py-4" x-ref="scroll">
<div class="space-y-3">
<template x-for="(m, i) in messages" :key="i">
<div class="flex" :class="m.role === 'user' ? 'justify-end' : 'justify-start'">
<div class="max-w-[85%] whitespace-pre-line rounded-2xl px-3.5 py-2.5 text-[13px] leading-relaxed"
:class="m.role === 'user' ? 'bg-indigo-600 text-white rounded-br-md' : 'bg-slate-100 text-slate-700 rounded-bl-md'"
x-html="m.text.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\*\*([^*]+?)\*\*/g,'<strong>$1</strong>')"></div>
</div>
</template>
<div x-show="loading" class="flex justify-start">
<div class="rounded-2xl rounded-bl-md bg-slate-100 px-4 py-3">
<div class="flex gap-1">
<span class="h-1.5 w-1.5 animate-bounce rounded-full bg-slate-400" style="animation-delay:0ms"></span>
<span class="h-1.5 w-1.5 animate-bounce rounded-full bg-slate-400" style="animation-delay:150ms"></span>
<span class="h-1.5 w-1.5 animate-bounce rounded-full bg-slate-400" style="animation-delay:300ms"></span>
</div>
</div>
</div>
</div>
<div x-show="messages.length <= 1 && suggestions.length" class="mt-4 space-y-2">
<template x-for="s in suggestions" :key="s">
<button @click="useSuggestion(s)" :disabled="loading"
class="flex w-full items-center gap-2 rounded-xl border border-slate-200 bg-white px-3.5 py-2.5 text-left text-[13px] font-medium text-slate-700 transition hover:border-indigo-200 hover:bg-indigo-50 disabled:opacity-50">
<span class="text-indigo-400"></span><span x-text="s"></span>
</button>
</template>
</div>
</div>
<div class="border-t border-slate-100 px-4 pb-4 pt-3">
<form @submit.prevent="send()" class="flex items-end gap-2">
<input type="text" x-ref="input" x-model="input" :disabled="loading" placeholder="Message Afia…"
class="flex-1 rounded-xl border border-slate-200 bg-slate-50 px-4 py-2.5 text-sm text-slate-700 placeholder-slate-400 focus:border-indigo-300 focus:bg-white focus:outline-none focus:ring-2 focus:ring-indigo-100">
<button type="submit" :disabled="loading || !input.trim()"
class="btn-fab shrink-0 disabled:opacity-40">
<svg class="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke-width="2.5" stroke="currentColor"><path stroke-linecap="round" stroke-linejoin="round" d="M4.5 10.5 12 3m0 0 7.5 7.5M12 3v18"/></svg>
</button>
</form>
<p class="mt-2 text-center text-[10px] text-slate-400">Afia can make mistakes verify important details.</p>
</div>
</section>
</div>