Files
Diabetix_v2/app/resources/js/Pages/Diabetix/Chat.vue
jeremy bayse 26c6d8031c Initial commit — Diabetix V2
Application Laravel 12 + Inertia + Vue 3 + Tailwind.
Fonctionnalités : dashboard glycémique, saisie de mesures, courbe SVG,
statistiques (jour/semaine/mois/trimestre), défis & badges, chat coach IA
(Gemini), paramètres profil avec palette de couleurs, pages auth redessinées,
emails transactionnels via Resend avec thème Diabetix.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-29 07:01:41 +02:00

74 lines
4.2 KiB
Vue

<script setup>
import { ref, watch, nextTick } from 'vue';
import { Head, useForm } from '@inertiajs/vue3';
import DiabetixLayout from '@/Layouts/DiabetixLayout.vue';
import CoachAvatar from '@/Components/Diabetix/CoachAvatar.vue';
const props = defineProps({
messages: Array,
});
const form = useForm({ body: '' });
const listRef = ref(null);
function send() {
if (!form.body.trim()) return;
form.post(route('chat.store'), {
preserveScroll: true,
onSuccess: () => form.reset('body'),
});
}
watch(() => props.messages.length, async () => {
await nextTick();
if (listRef.value) listRef.value.scrollTop = listRef.value.scrollHeight;
}, { immediate: true });
</script>
<template>
<Head title="Coach IA" />
<DiabetixLayout v-slot="{ tok, font }">
<div :style="{ display: 'flex', flexDirection: 'column', height: 'calc(100vh - 78px)', background: tok.bg }">
<div :style="{ background: tok.white, padding: '12px 16px', display: 'flex', alignItems: 'center', gap: '10px', borderBottom: '1px solid ' + tok.border, flexShrink: 0 }">
<CoachAvatar :size="36" :tok="tok" />
<div>
<div :style="{ fontFamily: font.title, fontSize: '16px', fontWeight: 600, color: tok.text }">Coach IA</div>
<div :style="{ fontSize: '11px', color: tok.primary }">🟢 En ligne · Répond en quelques secondes</div>
</div>
</div>
<div ref="listRef" style="flex:1;overflow-y:auto;padding:16px;display:flex;flex-direction:column;gap:12px;">
<div v-for="(msg, i) in messages" :key="msg.id ?? i"
:style="{ display: 'flex', flexDirection: 'column', alignItems: msg.sender === 'coach' ? 'flex-start' : 'flex-end', gap: '5px' }">
<div :style="{ display: 'flex', alignItems: 'flex-end', gap: '8px', flexDirection: msg.sender === 'coach' ? 'row' : 'row-reverse' }">
<CoachAvatar v-if="msg.sender === 'coach'" :size="28" :tok="tok" />
<div :style="{
maxWidth: '78%',
background: msg.sender === 'coach' ? tok.light : tok.primary,
color: msg.sender === 'coach' ? tok.text : '#fff',
borderRadius: msg.sender === 'coach' ? '14px 14px 14px 3px' : '14px 14px 3px 14px',
padding: '10px 14px', fontSize: '13px', lineHeight: 1.5,
}">{{ msg.body }}</div>
</div>
<div v-if="msg.actions && msg.actions.length" :style="{ display: 'flex', flexWrap: 'wrap', gap: '6px', marginLeft: msg.sender === 'coach' ? '36px' : 0 }">
<button v-for="(a, j) in msg.actions" :key="j" :style="{
padding: '5px 13px', borderRadius: '20px', background: tok.white,
border: '1.5px solid ' + tok.primary, fontSize: '11px',
color: tok.primary, fontWeight: 500, cursor: 'pointer',
}">{{ a }}</button>
</div>
<div :style="{ fontSize: '9px', color: tok.muted, paddingLeft: msg.sender === 'coach' ? '36px' : 0 }">{{ msg.time }}</div>
</div>
</div>
<div :style="{ padding: '10px 14px', background: tok.white, borderTop: '1px solid ' + tok.border, flexShrink: 0, display: 'flex', gap: '8px', alignItems: 'center' }">
<input v-model="form.body" @keydown.enter="send"
placeholder="Écrire au coach..."
:style="{ flex: 1, padding: '10px 14px', borderRadius: '20px', border: '1.5px solid ' + tok.border, background: tok.bg, fontSize: '13px', color: tok.text, outline: 'none' }" />
<button @click="send" :disabled="form.processing"
:style="{ width: '38px', height: '38px', borderRadius: '50%', background: tok.primary, border: 'none', color: '#fff', fontSize: '17px', cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center', opacity: form.processing ? 0.6 : 1 }"></button>
</div>
</div>
</DiabetixLayout>
</template>