mirror of
https://github.com/System-End/identity-vault.git
synced 2026-04-19 18:35:13 +00:00
* temp commit * lemme do it * nope * let them do it too * collab invite model * better visuals on progman * waow * danger will robinson * show apps on backend & link user * first pass on app auditability! * no lastnaming admins * async frame that shit! * waugh * can't add yourself * fix reinvite * sidebar badging * lint... * gotta be on the app! * let that get rescued by applcon * already in revoke_all_authorizations * woag * the routes you grew up with no longer exist * what would the UI for that even be? * sorch * much better! * frickin validations
167 lines
5.1 KiB
Ruby
167 lines
5.1 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
class Components::Sidebar < Components::Base
|
|
include Phlex::Rails::Helpers::LinkTo
|
|
include Phlex::Rails::Helpers::CurrentPage
|
|
|
|
register_value_helper :current_identity
|
|
register_value_helper :signed_in?
|
|
register_output_helper :copy_to_clipboard
|
|
register_output_helper :vite_image_tag
|
|
|
|
def initialize(current_path:)
|
|
@current_path = current_path
|
|
end
|
|
|
|
def view_template
|
|
render_mobile_toggle
|
|
render_overlay
|
|
|
|
nav(class: "sidebar", id: "sidebar") do
|
|
render_sidebar_brand
|
|
render_navigation
|
|
render_user_section if signed_in?
|
|
end
|
|
|
|
render_toggle_script
|
|
end
|
|
|
|
private
|
|
|
|
def nav_items
|
|
items = [
|
|
{ label: t("sidebar.home"), path: root_path, icon: "home" }
|
|
]
|
|
|
|
items << { label: t("sidebar.edit_info"), path: edit_identity_path, icon: "person" }
|
|
|
|
# Add verification link if user needs to submit or resubmit
|
|
if current_identity.present?
|
|
status = current_identity.verification_status
|
|
if status == "needs_submission" || status == "pending"
|
|
items << {
|
|
label: t("sidebar.verification"),
|
|
path: new_verifications_path,
|
|
icon: status == "pending" ? "clock" : "card-id"
|
|
}
|
|
end
|
|
end
|
|
|
|
items << { label: t("sidebar.addresses"), path: addresses_path, icon: "email" }
|
|
items << { label: t("sidebar.security"), path: security_path, icon: "private" }
|
|
|
|
# Add developer link if developer mode is enabled or user is a program manager/super admin
|
|
if current_identity.present? && (current_identity.developer_mode? || current_identity.backend_user&.program_manager? || current_identity.backend_user&.super_admin?)
|
|
pending_count = current_identity.pending_collaboration_invitations.count
|
|
items << { label: t("sidebar.developer"), path: developer_apps_path, icon: "code", badge: pending_count }
|
|
end
|
|
|
|
items << { label: t("sidebar.docs"), path: docs_path, icon: "docs" }
|
|
|
|
if current_identity.present? && current_identity.active_for_backend?
|
|
items << { label: t("sidebar.backend"), path: backend_root_path, icon: "admin" }
|
|
end
|
|
|
|
items
|
|
end
|
|
|
|
def render_mobile_toggle
|
|
button(class: "sidebar-toggle", onclick: safe("toggleSidebar()"), "aria-label": "Toggle sidebar") do
|
|
svg(
|
|
width: "24",
|
|
height: "24",
|
|
viewBox: "0 0 24 24",
|
|
fill: "none",
|
|
stroke: "currentColor",
|
|
stroke_width: "2.5",
|
|
stroke_linecap: "round",
|
|
stroke_linejoin: "round"
|
|
) do |s|
|
|
s.line(x1: "4", y1: "6", x2: "20", y2: "6")
|
|
s.line(x1: "4", y1: "12", x2: "20", y2: "12")
|
|
s.line(x1: "4", y1: "18", x2: "20", y2: "18")
|
|
end
|
|
end
|
|
end
|
|
|
|
def render_overlay
|
|
div(class: "sidebar-overlay", onclick: safe("toggleSidebar()"))
|
|
end
|
|
|
|
def render_navigation
|
|
div(class: "sidebar-nav") do
|
|
nav_items.each do |item|
|
|
render_nav_item(**item)
|
|
end
|
|
end
|
|
end
|
|
|
|
def render_nav_item(label:, path:, icon: nil, badge: nil)
|
|
is_active = @current_path == path
|
|
|
|
link_to(path, class: [ "sidebar-nav-item", ("active" if is_active) ].compact.join(" ")) do
|
|
span(class: "nav-icon") { inline_icon(icon, size: 24) } if icon
|
|
span(class: "nav-label") { label }
|
|
span(class: "nav-badge") { badge.to_s } if badge && badge > 0
|
|
end
|
|
end
|
|
|
|
def render_user_section
|
|
div(class: "sidebar-user") do
|
|
render_user_info
|
|
render_logout_button
|
|
end
|
|
end
|
|
|
|
def render_user_info
|
|
div(class: "user-info") do
|
|
copy_to_clipboard current_identity.public_id, tooltip_direction: "e", label: "click to copy your account ID..." do
|
|
div(class: "user-avatar") do
|
|
span { current_identity.first_name&.first || "?" }
|
|
end
|
|
end
|
|
div(class: "user-details") do
|
|
div(class: "user-name") do
|
|
plain current_identity.first_name
|
|
whitespace
|
|
plain current_identity.last_name
|
|
end
|
|
div(class: "user-email") { current_identity.primary_email }
|
|
end
|
|
end
|
|
end
|
|
|
|
def render_logout_button
|
|
form_with(url: logout_path, method: :delete, class: "logout-form") do
|
|
button(type: "submit", class: "logout-button secondary") do
|
|
plain t "sidebar.logout"
|
|
span(class: "logout-icon") { inline_icon("door-leave", size: 18) }
|
|
end
|
|
end
|
|
end
|
|
|
|
def render_sidebar_brand
|
|
div(class: "sidebar-brand") do
|
|
vite_image_tag("images/hc-square.png", alt: "Hack Club logo", class: "brand-logo")
|
|
h1 { I18n.t(".brand") }
|
|
button(id: "lightswitch", class: "lightswitch-btn", type: "button", "aria-label": "Toggle theme") do
|
|
span(class: "lightswitch-moon") { inline_icon("moon-fill", size: 16) }
|
|
span(class: "lightswitch-sun", style: "display: none;") { inline_icon("sun", size: 16) }
|
|
end
|
|
end
|
|
render Components::EnvironmentBanner.new
|
|
end
|
|
|
|
def render_toggle_script
|
|
script do
|
|
raw safe <<~JS
|
|
function toggleSidebar() {
|
|
const sidebar = document.getElementById('sidebar');
|
|
const overlay = document.querySelector('.sidebar-overlay');
|
|
sidebar.classList.toggle('mobile-open');
|
|
overlay.classList.toggle('active');
|
|
}
|
|
JS
|
|
end
|
|
end
|
|
end
|