Files
shelflife/app/components/user/profile_view.rb
Dan Milne 311ecafb74
Some checks failed
CI / scan_ruby (push) Has been cancelled
CI / lint (push) Has been cancelled
CI / test (push) Has been cancelled
More complete oauth. Handle deleted OauthApp by re-registering
2025-10-08 08:19:39 +11:00

168 lines
7.5 KiB
Ruby

class Components::User::ProfileView < Components::Base
# include Rails.application.routes.url_helpers
def initialize(user:)
@user = user
end
def view_template
div(class: "min-h-screen bg-gray-50") do
render Components::Shared::NavigationView.new
div(class: "pt-20 px-4") do
div(class: "max-w-2xl mx-auto") do
div(class: "bg-white rounded-lg shadow-md") do
# Header
div(class: "px-6 py-8 border-b border-gray-200") do
div(class: "flex items-center") do
div(class: "w-16 h-16 bg-primary-100 rounded-full flex items-center justify-center") do
span(class: "text-2xl font-bold text-primary-700") do
(@user.name.present? ? @user.name.first : @user.email_address.first).upcase
end
end
div(class: "ml-4") do
h1(class: "text-2xl font-bold text-gray-900") { "Your Profile" }
p(class: "text-gray-600") { @user.name.present? ? @user.name : @user.email_address }
end
end
end
# Profile Details
div(class: "px-6 py-6") do
dl(class: "grid grid-cols-1 gap-6") do
div do
dt(class: "text-sm font-medium text-gray-500") { "Name" }
dd(class: "mt-1 text-sm text-gray-900") { @user.name.present? ? @user.name : "Not set" }
end
div do
dt(class: "text-sm font-medium text-gray-500") { "Email Address" }
dd(class: "mt-1 text-sm text-gray-900") { @user.email_address }
end
div do
dt(class: "text-sm font-medium text-gray-500") { "Member Since" }
dd(class: "mt-1 text-sm text-gray-900") { @user.created_at.strftime("%B %d, %Y") }
end
div do
dt(class: "text-sm font-medium text-gray-500") { "Recent Scans" }
dd(class: "mt-1 text-sm text-gray-900") do
span { @user.scans.count.to_s }
span(class: "text-gray-500 ml-1") { "total scans" }
end
end
end
end
# Settings Section
div(class: "px-6 py-6 border-t border-gray-200") do
h3(class: "text-lg font-medium text-gray-900 mb-6") { "Settings" }
form_with(
model: @user,
url: "/profile/settings",
method: :patch,
local: false,
data: { controller: "settings-form" },
class: "space-y-4"
) do |form|
# Hide invalid barcodes setting
div(class: "flex items-center justify-between") do
div do
dt(class: "text-sm font-medium text-gray-700") { "Hide Invalid ISBNs/GTIN barcodes" }
dd(class: "text-xs text-gray-500 mt-1") { "Hide products with invalid GTIN check digits or non-ISBN barcodes from listings" }
end
div(class: "ml-4") do
label(class: "relative inline-flex items-center cursor-pointer") do
form.check_box(
:hide_invalid_barcodes,
{
checked: @user.hide_invalid_barcodes?,
data: { action: "change->settings-form#updateSetting" },
class: "sr-only peer"
},
"true",
"false"
)
div(class: "w-11 h-6 bg-gray-200 peer-focus:outline-none peer-focus:ring-4 peer-focus:ring-primary-300 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary-600")
end
end
end
# Status message area
div(
id: "settings-status",
data: { settings_form_target: "status" },
class: "hidden text-sm mt-2"
)
end
end
# API Configuration Section
div(class: "px-6 py-6 border-t border-gray-200") do
h3(class: "text-lg font-medium text-gray-900 mb-6") { "TBDB Integration" }
div(class: "space-y-6") do
# OAuth Connection Status
div do
dt(class: "text-sm font-medium text-gray-700 mb-2") { "OAuth Connection" }
dd(class: "text-xs text-gray-500 mb-3") { "Secure OAuth connection to TheBookDB.info for enhanced product data access." }
if @user.has_oauth_connection?
div(class: "flex items-center justify-between p-3 bg-green-50 border border-green-200 rounded") do
div do
div(class: "text-sm font-medium text-green-800") { "Connected to TBDB" }
if @user.oauth_token_expired?
div(class: "text-xs text-amber-600 mt-1") { "Token expired - will refresh automatically" }
else
div(class: "text-xs text-green-600 mt-1") { "Active connection" }
end
end
a(
href: auth_tbdb_disconnect_path,
data: {
turbo_method: "delete",
turbo_confirm: "Are you sure you want to disconnect from TBDB?"
},
class: "text-sm text-red-600 hover:text-red-700 font-medium"
) { "Disconnect" }
end
else
div(class: "flex items-center justify-between p-3 bg-gray-50 border border-gray-200 rounded") do
div do
div(class: "text-sm font-medium text-gray-700") { "Not Connected" }
div(class: "text-xs text-gray-500 mt-1") { "Connect for seamless API access" }
end
a(
href: auth_tbdb_path,
class: "inline-flex items-center px-4 py-2 border border-transparent text-sm font-medium rounded-md text-white bg-primary-600 hover:bg-primary-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary-500"
) { "Connect to TBDB" }
end
end
end
end
end
# Actions
div(class: "px-6 py-4 bg-gray-50 border-t border-gray-200") do
div(class: "flex justify-end space-x-4") do
a(href: edit_profile_path, class: "text-primary-600 hover:text-primary-700 font-medium") do
"Edit Profile"
end
a(href: change_password_path, class: "text-gray-600 hover:text-gray-900 font-medium") do
"Change Password"
end
a(href: signout_path, method: :delete, class: "text-red-600 hover:text-red-700 font-medium") do
"Sign Out"
end
end
end
end
end
end
end
end
end