2828 <%= render "chats/form" , chat : @chat , assistant : @chat . assistant %>
2929 </ div >
3030 </ div >
31+
32+ <!-- Chart Section -->
33+ < div class ="mt-8 bg-white rounded-lg shadow-sm border border-stone-200 p-6 ">
34+ < h2 class ="text-stone-700 font-light text-2xl mb-4 "> Chat Activity - Last 30 Days</ h2 >
35+ < div class ="w-full " style ="height: 300px; ">
36+ < canvas id ="chatsPerDayChart "> </ canvas >
37+ </ div >
38+ </ div >
39+
3140 < div >
3241 < h1 class ="text-stone-700 font-light text-3xl mt-6 "> Recent Chats</ h1 >
3342 <%= render "shared/chat_list" , chats : @assistant . chats . limit ( 10 ) . order ( created_at : :desc ) %>
4655 </ div >
4756 </ div >
4857</ div >
58+ < script src ="
https://cdn.jsdelivr.net/npm/[email protected] /dist/chart.umd.min.js "
> </ script > 4959< script >
5060 document . querySelector ( 'a[href="#"]' ) . addEventListener ( "click" , function ( e ) {
5161 e . preventDefault ( ) ;
5464 document . getElementById ( "close-modal" ) . addEventListener ( "click" , function ( ) {
5565 document . getElementById ( "details-modal" ) . classList . add ( "hidden" ) ;
5666 } ) ;
67+
68+ // Initialize Chart.js
69+ function initializeChart ( ) {
70+ const ctx = document . getElementById ( 'chatsPerDayChart' ) ;
71+ if ( ! ctx ) return ;
72+
73+ // Destroy existing chart if it exists to prevent duplicates
74+ if ( window . chatsChart ) {
75+ window . chatsChart . destroy ( ) ;
76+ }
77+
78+ const chartData = <%= raw @chats_per_day . to_json %> ;
79+ const labels = chartData . map ( d => {
80+ const date = new Date ( d . date ) ;
81+ return date . toLocaleDateString ( 'en-US' , { month : 'short' , day : 'numeric' } ) ;
82+ } ) ;
83+ const data = chartData . map ( d => d . count ) ;
84+
85+ window . chatsChart = new Chart ( ctx , {
86+ type : 'line' ,
87+ data : {
88+ labels : labels ,
89+ datasets : [ {
90+ label : 'Chats per Day' ,
91+ data : data ,
92+ borderColor : '#0ea5e9' ,
93+ backgroundColor : 'rgba(14, 165, 233, 0.1)' ,
94+ tension : 0.3 ,
95+ fill : true ,
96+ pointRadius : 3 ,
97+ pointHoverRadius : 5 ,
98+ pointBackgroundColor : '#0ea5e9' ,
99+ pointBorderColor : '#fff' ,
100+ pointBorderWidth : 2
101+ } ]
102+ } ,
103+ options : {
104+ responsive : true ,
105+ maintainAspectRatio : false ,
106+ plugins : {
107+ legend : {
108+ display : false
109+ } ,
110+ tooltip : {
111+ backgroundColor : 'rgba(0, 0, 0, 0.8)' ,
112+ padding : 12 ,
113+ titleFont : {
114+ size : 13
115+ } ,
116+ bodyFont : {
117+ size : 13
118+ } ,
119+ callbacks : {
120+ label : function ( context ) {
121+ return 'Chats: ' + context . parsed . y ;
122+ }
123+ }
124+ }
125+ } ,
126+ scales : {
127+ y : {
128+ beginAtZero : true ,
129+ ticks : {
130+ stepSize : 1 ,
131+ font : {
132+ size : 11
133+ }
134+ } ,
135+ grid : {
136+ color : 'rgba(0, 0, 0, 0.05)'
137+ }
138+ } ,
139+ x : {
140+ ticks : {
141+ maxRotation : 45 ,
142+ minRotation : 45 ,
143+ font : {
144+ size : 10
145+ }
146+ } ,
147+ grid : {
148+ display : false
149+ }
150+ }
151+ }
152+ }
153+ } ) ;
154+ }
155+
156+ // Listen for both DOMContentLoaded and Turbo events
157+ document . addEventListener ( 'DOMContentLoaded' , initializeChart ) ;
158+ document . addEventListener ( 'turbo:load' , initializeChart ) ;
57159</ script >
0 commit comments