Refactor chat form and AI greeting with flexible partials
- Extract message form to a reusable partial with dynamic context support - Create flexible AI greeting partial for consistent welcome messages - Simplify chat and sidebar views by leveraging new partials - Add support for different form scenarios (chat, new chat, sidebar) - Improve code modularity and reduce duplication
This commit is contained in:
@@ -26,49 +26,12 @@
|
||||
<% end %>
|
||||
<% else %>
|
||||
<!-- Show welcome message when chat has no messages -->
|
||||
<div class="flex items-start gap-3 mb-4 w-full">
|
||||
<%= render "layouts/shared/ai_avatar" %>
|
||||
<div class="p-4 max-w-[85%] text-gray-800">
|
||||
<p>Hey <%= Current.user&.first_name || 'there' %>! I'm an AI built by Maybe to help with your finances. How can I assist you today?</p>
|
||||
</div>
|
||||
</div>
|
||||
<%= render "layouts/shared/ai_greeting", context: 'chat' %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="border-t border-gray-200 p-4">
|
||||
<%= form_with model: [@chat, @message], class: "relative", data: { controller: "message-form", action: "turbo:submit-end->message-form#reset turbo:submit-end->chat-scroll#scrollToBottom" } do |f| %>
|
||||
<div class="bg-white border border-gray-300 rounded-lg overflow-hidden">
|
||||
<div class="px-3 py-2">
|
||||
<%= f.text_area :content,
|
||||
placeholder: "Ask anything...",
|
||||
class: "w-full border-0 focus:ring-0 resize-none text-sm",
|
||||
rows: 1,
|
||||
data: {
|
||||
controller: "textarea-autogrow",
|
||||
action: "input->textarea-autogrow#resize keydown->message-form#checkSubmit"
|
||||
} %>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center px-2 py-2 border-t border-gray-200">
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("plus") %>
|
||||
</button>
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("command") %>
|
||||
</button>
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("at-sign") %>
|
||||
</button>
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("sparkles") %>
|
||||
</button>
|
||||
|
||||
<button type="submit" class="ml-auto p-1.5 text-gray-500 hover:text-gray-700 rounded-md" data-message-form-target="submit">
|
||||
<%= icon("arrow-up") %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render "messages/form", chat: @chat, message: @message, scroll_behavior: true %>
|
||||
</div>
|
||||
</div>
|
||||
41
app/views/layouts/shared/_ai_greeting.html.erb
Normal file
41
app/views/layouts/shared/_ai_greeting.html.erb
Normal file
@@ -0,0 +1,41 @@
|
||||
<%#
|
||||
This partial renders the AI greeting message.
|
||||
|
||||
Parameters:
|
||||
- context: Either 'chat' (for existing chat) or 'default' (for new chat)
|
||||
%>
|
||||
|
||||
<% context ||= 'default' %>
|
||||
|
||||
<div class="flex items-start gap-1 mt-4 w-full">
|
||||
<%= render "layouts/shared/ai_avatar" %>
|
||||
<div class="pt-2 pr-1 max-w-[85%] text-gray-800 text-sm">
|
||||
<% if context == 'chat' %>
|
||||
<p>Hey <%= Current.user&.first_name || 'there' %>! I'm an AI built by Maybe to help with your finances. How can I assist you today?</p>
|
||||
<% else %>
|
||||
<p>Hey <%= Current.user&.first_name || 'there' %>! I'm an AI built by Maybe to help with your finances. I have access to the web and your account data.</p>
|
||||
|
||||
<div class="mt-4 text-gray-600">
|
||||
You can use <span class="bg-white border border-gray-200 px-1.5 py-0.5 rounded font-mono text-xs">/</span> to access commands
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<p class="text-gray-600 mb-3">Here's a few questions you can ask:</p>
|
||||
|
||||
<div class="space-y-2">
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("bar-chart-2") %> Evaluate investment portfolio
|
||||
</button>
|
||||
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("credit-card") %> Show spending insights
|
||||
</button>
|
||||
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("alert-triangle") %> Find unusual patterns
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
@@ -101,74 +101,11 @@
|
||||
</div>
|
||||
<% end %>
|
||||
<% else %>
|
||||
<div class="flex items-start gap-1 mt-4 w-full">
|
||||
<%= render "layouts/shared/ai_avatar" %>
|
||||
<div class="pr-1 max-w-[85%] text-gray-800">
|
||||
<p>Hey <%= Current.user&.first_name || 'there' %>! I'm an AI built by Maybe to help with your finances. How can I assist you today?</p>
|
||||
</div>
|
||||
</div>
|
||||
<%= render "layouts/shared/ai_greeting", context: 'chat' %>
|
||||
<% end %>
|
||||
</div>
|
||||
<% else %>
|
||||
<% if Current.user %>
|
||||
<div class="flex items-start gap-1 mt-4 w-full">
|
||||
<%= render "layouts/shared/ai_avatar" %>
|
||||
<div class="pr-1 max-w-[85%] text-gray-800">
|
||||
<p>Hey <%= Current.user&.first_name || 'there' %>! I'm an AI built by Maybe to help with your finances. I have access to the web and your account data.</p>
|
||||
|
||||
<div class="mt-4 text-gray-600">
|
||||
You can use <span class="bg-gray-200 px-2 py-1 rounded">/ </span> to access commands
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<p class="text-gray-600 mb-3">Here's a few questions you can ask:</p>
|
||||
|
||||
<div class="space-y-2">
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("bar-chart-2") %> Evaluate investment portfolio
|
||||
</button>
|
||||
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("credit-card") %> Show spending insights
|
||||
</button>
|
||||
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("alert-triangle") %> Find unusual patterns
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="flex items-start gap-1 mt-4 w-full">
|
||||
<%= render "layouts/shared/ai_avatar" %>
|
||||
<div class="p-4 max-w-[85%] text-gray-800">
|
||||
<p>Hey there! I'm an AI built by Maybe to help with your finances. I have access to the web and your account data.</p>
|
||||
|
||||
<div class="mt-4 text-gray-600">
|
||||
You can use <span class="bg-gray-200 px-2 py-1 rounded">/ </span> to access commands
|
||||
</div>
|
||||
|
||||
<div class="mt-4">
|
||||
<p class="text-gray-600 mb-3">Here's a few questions you can ask:</p>
|
||||
|
||||
<div class="space-y-2">
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("bar-chart-2") %> Evaluate investment portfolio
|
||||
</button>
|
||||
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("credit-card") %> Show spending insights
|
||||
</button>
|
||||
|
||||
<button class="w-full flex items-center gap-2 bg-white border border-gray-200 rounded-full py-2 px-4 text-left hover:bg-gray-50">
|
||||
<%= icon("alert-triangle") %> Find unusual patterns
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render "layouts/shared/ai_greeting", context: 'default' %>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -187,73 +124,9 @@
|
||||
|
||||
<div class="px-4 py-3">
|
||||
<% if Current.user && @chat.present? %>
|
||||
<%= form_with model: [@chat, @message], class: "relative", data: { controller: "message-form", action: "turbo:submit-end->message-form#reset turbo:submit-end->chat-scroll#scrollToBottom" } do |f| %>
|
||||
<div class="bg-white border border-gray-300 rounded-lg overflow-hidden">
|
||||
<div class="px-3 py-2">
|
||||
<%= f.text_area :content,
|
||||
placeholder: "Ask anything ...",
|
||||
class: "w-full border-0 focus:ring-0 resize-none text-sm",
|
||||
rows: 1,
|
||||
data: {
|
||||
controller: "textarea-autogrow",
|
||||
action: "input->textarea-autogrow#resize keydown->message-form#checkSubmit"
|
||||
} %>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center px-2 py-2 border-t border-gray-200">
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("plus") %>
|
||||
</button>
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("command") %>
|
||||
</button>
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("at-sign") %>
|
||||
</button>
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("sparkles") %>
|
||||
</button>
|
||||
|
||||
<button type="submit" class="ml-auto p-1.5 text-gray-500 hover:text-gray-700 rounded-md" data-message-form-target="submit">
|
||||
<%= icon("arrow-up") %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render "messages/form", chat: @chat, message: @message, scroll_behavior: true %>
|
||||
<% else %>
|
||||
<%= form_with url: chats_path, method: :post, class: "relative", data: { controller: "message-form", action: "turbo:submit-end->message-form#reset turbo:submit-end->chat-scroll#scrollToBottom" } do |f| %>
|
||||
<div class="bg-white border border-gray-300 rounded-lg overflow-hidden">
|
||||
<div class="px-3 py-2">
|
||||
<%= f.text_area :content,
|
||||
placeholder: "Ask anything ...",
|
||||
class: "w-full border-0 focus:ring-0 resize-none text-sm",
|
||||
rows: 1,
|
||||
data: {
|
||||
controller: "textarea-autogrow",
|
||||
action: "input->textarea-autogrow#resize keydown->message-form#checkSubmit"
|
||||
} %>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center px-2 py-2 border-t border-gray-200">
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("plus") %>
|
||||
</button>
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("command") %>
|
||||
</button>
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("at-sign") %>
|
||||
</button>
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("sparkles") %>
|
||||
</button>
|
||||
|
||||
<button type="submit" class="ml-auto p-1.5 text-gray-500 hover:text-gray-700 rounded-md" data-message-form-target="submit">
|
||||
<%= icon("arrow-up") %>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
<%= render "messages/form", scroll_behavior: true %>
|
||||
<% end %>
|
||||
<p class="text-xs text-gray-500 text-center mt-2">AI may make mistakes. Make sure to double check responses.</p>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,41 @@
|
||||
<%= form_with model: [chat, message], class: "relative", data: { controller: "message-form", action: "turbo:submit-end->message-form#reset" } do |f| %>
|
||||
<%
|
||||
# This partial can be used in multiple contexts:
|
||||
# - In a chat show page: form_with model: [chat, message]
|
||||
# - In a new chat context: form_with url: chats_path, method: :post
|
||||
# - In a sidebar: with additional scroll behavior
|
||||
#
|
||||
# Parameters:
|
||||
# - chat: The chat object (optional, if creating a new chat)
|
||||
# - message: The message object (optional, if creating a new chat)
|
||||
# - form_options: Additional options for the form (default: {})
|
||||
# - scroll_behavior: Whether to include scroll behavior (default: false)
|
||||
%>
|
||||
|
||||
<%
|
||||
# Set up default values
|
||||
form_options ||= {}
|
||||
scroll_behavior ||= false
|
||||
|
||||
# Determine form parameters based on context
|
||||
if defined?(chat) && chat.present? && defined?(message) && message.present?
|
||||
form_params = { model: [chat, message] }
|
||||
else
|
||||
form_params = { url: chats_path, method: :post }
|
||||
end
|
||||
|
||||
# Merge form options
|
||||
form_params.merge!(form_options)
|
||||
|
||||
# Set up controller and actions
|
||||
controller_data = { controller: "message-form", action: "turbo:submit-end->message-form#reset" }
|
||||
if scroll_behavior
|
||||
controller_data[:action] += " turbo:submit-end->chat-scroll#scrollToBottom"
|
||||
end
|
||||
%>
|
||||
|
||||
<%= form_with **form_params, class: "relative", data: controller_data do |f| %>
|
||||
<div class="bg-white border border-gray-300 rounded-lg overflow-hidden">
|
||||
<div class="px-3 py-2">
|
||||
<div class="px-3 pt-2">
|
||||
<%= f.text_area :content,
|
||||
placeholder: "Ask anything...",
|
||||
class: "w-full border-0 focus:ring-0 resize-none text-sm",
|
||||
@@ -11,7 +46,7 @@
|
||||
} %>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center px-2 py-2 border-t border-gray-200">
|
||||
<div class="flex items-center px-2 pb-2">
|
||||
<button type="button" class="p-1.5 text-gray-500 hover:text-gray-700 rounded-md">
|
||||
<%= icon("plus") %>
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user