hackatime/app/views/users/edit.html.erb
2025-06-23 16:09:25 -04:00

386 lines
20 KiB
Text

<% content_for :title do %>
<%= @is_own_settings ? "My Settings" : "Settings | #{@user.username}" %>
<% end %>
<div class="max-w-6xl mx-auto p-6 space-y-6">
<header class="text-center mb-8">
<h1 class="text-4xl font-bold text-white mb-2">
<%= @is_own_settings ? "My Settings" : "Settings for #{@user.username}" %>
</h1>
<p class="text-muted text-lg">Change your Hackatime experience and preferences</p>
</header>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-red-600/10 rounded">
<span class="text-2xl">🚀</span>
</div>
<h2 class="text-xl font-semibold text-white">Time Tracking Wizard</h2>
</div>
<p class="text-gray-300 mb-4">Get started with tracking your coding time in just a few minutes.</p>
<%= link_to "Set up time tracking", my_wakatime_setup_path,
class: "inline-flex items-center gap-2 px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
</div>
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-red-600/10 rounded">
<span class="text-2xl">🌍</span>
</div>
<h2 class="text-xl font-semibold text-white" id="user_timezone">Timezone</h2>
</div>
<%= form_with model: @user,
url: @is_own_settings ? my_settings_path : settings_user_path(@user),
method: :patch, local: false,
class: "space-y-4" do |f| %>
<div>
<%= f.label :timezone, "Your timezone", class: "block text-sm font-medium text-gray-200 mb-2" %>
<%= f.select :timezone,
TZInfo::Timezone.all.map(&:identifier).sort,
{ include_blank: @user.timezone.blank? },
{ class: "w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded text-white focus:border-primary focus:ring-1 focus:ring-primary" } %>
</div>
<p class="text-xs text-gray-400">This affects how your activity graph and other time-based features are displayed.</p>
<%= f.submit "Save Settings", class: "w-full px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
<% end %>
</div>
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-red-600/10 rounded">
<span class="text-2xl">⚙️</span>
</div>
<h2 class="text-xl font-semibold text-white" id="user_hackatime_extension">Extension Settings</h2>
</div>
<%= form_with model: @user,
url: @is_own_settings ? my_settings_path : settings_user_path(@user),
method: :patch, local: false,
class: "space-y-4" do |f| %>
<div>
<%= f.label :hackatime_extension_text_type, "Status bar text style", class: "block text-sm font-medium text-gray-200 mb-2" %>
<%= f.select :hackatime_extension_text_type,
User.hackatime_extension_text_types.keys.map { |key| [key.humanize, key] },
{},
{ class: "w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded text-white focus:border-primary focus:ring-1 focus:ring-primary" } %>
</div>
<%= f.submit "Save Settings", class: "w-full px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
<% end %>
</div>
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-red-600/10 rounded">
<span class="text-2xl">💬</span>
</div>
<h2 class="text-xl font-semibold text-white" id="user_slack_status">Slack Integration</h2>
</div>
<div class="space-y-4">
<div>
<h3 class="text-lg font-medium text-white mb-2">Status Updates</h3>
<p class="text-gray-300 text-sm mb-3">When you're hacking on a project, Hackatime can update your Slack status so you can show it off!</p>
<% unless @can_enable_slack_status %>
<%= link_to "Re-authorize with Slack", slack_auth_path,
class: "inline-flex items-center gap-2 px-3 py-2 bg-gray-700 hover:bg-gray-600 text-gray-200 text-sm font-medium rounded transition-colors duration-200 mb-3" %>
<% end %>
<%= form_with model: @user,
url: @is_own_settings ? my_settings_path : settings_user_path(@user),
method: :patch, local: false do |f| %>
<div class="flex items-center gap-3">
<%= f.check_box :uses_slack_status,
class: "w-4 h-4 text-primary border-gray-600 rounded focus:ring-primary bg-gray-800" %>
<%= f.label :uses_slack_status, "Update my Slack status automatically",
class: "text-sm text-gray-200" %>
</div>
<%= f.submit "Save", class: "mt-3 px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
<% end %>
</div>
<div class="border-t border-gray-700 pt-4">
<h3 class="text-lg font-medium text-white mb-2" id="user_slack_notifications">Channel Notifications</h3>
<% if @enabled_sailors_logs.any? %>
<p class="text-gray-300 text-sm mb-2">You have notifications enabled for the following channels:</p>
<ul class="space-y-1 mb-3">
<% @enabled_sailors_logs.each do |sl| %>
<li class="text-xs text-gray-300 px-2 py-1 bg-gray-800 rounded">
<%= render "shared/slack_channel_mention", channel_id: sl.slack_channel_id %>
</li>
<% end %>
</ul>
<% else %>
<p class="text-gray-300 text-sm mb-3">You have no notifications enabled.</p>
<% end %>
<p class="text-xs text-gray-400">
You can enable notifications for specific channels by running <code class="px-1 py-0.5 bg-gray-800 rounded text-gray-200">/sailorslog on</code> in the Slack channel.
</p>
</div>
</div>
</div>
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-red-600/10 rounded">
<span class="text-2xl">🔒</span>
</div>
<h2 class="text-xl font-semibold text-white" id="user_privacy">Privacy Settings</h2>
</div>
<%= form_with model: @user,
url: @is_own_settings ? my_settings_path : settings_user_path(@user),
method: :patch, local: false,
class: "space-y-4" do |f| %>
<div class="flex items-center gap-3">
<%= f.check_box :allow_public_stats_lookup,
class: "w-4 h-4 text-primary border-gray-600 rounded focus:ring-primary bg-gray-800" %>
<%= f.label :allow_public_stats_lookup, "Allow public stats lookup",
class: "text-sm text-gray-200" %>
</div>
<p class="text-xs text-gray-400">When enabled, others can view your coding statistics through public APIs.</p>
<%= f.submit "Save Settings", class: "w-full px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
<% end %>
</div>
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-red-600/10 rounded">
<span class="text-2xl">🏆</span>
</div>
<h2 class="text-xl font-semibold text-white" id="user_beta_features">Leaderboard Settings</h2>
</div>
<p class="text-gray-300 text-sm mb-4">Customize how you see the leaderboard</p>
<%= render "timezone_leaderboard_toggle", user: @user %>
</div>
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200 md:col-span-2">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-red-600/10 rounded">
<span class="text-2xl">🔗</span>
</div>
<h2 class="text-xl font-semibold text-white" id="user_github_account">Connected Accounts</h2>
</div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6">
<div class="space-y-3">
<h3 class="text-lg font-medium text-white">GitHub Account</h3>
<p class="text-gray-300 text-sm">This is used to show your active projects on the leaderboard & current hacking activity on the dashboard.</p>
<% if @user.github_uid.present? %>
<div class="flex items-center gap-2 p-3 bg-gray-800 border border-gray-600 rounded">
<span class="text-green-400">✅</span>
<span class="text-gray-200 text-sm">Connected: <%= link_to "@#{@user.github_username}", "https://github.com/#{@user.github_username}", target: "_blank", class: "text-primary hover:text-primary/80 underline" %></span>
</div>
<% unless @user.github_access_token.present? %>
<%= link_to "Relink GitHub Account", github_auth_path, data: { turbo: "false" },
class: "inline-flex items-center gap-2 px-3 py-2 bg-primary text-white text-sm font-medium rounded transition-colors duration-200" %>
<% end %>
<% else %>
<%= link_to "Link GitHub Account", github_auth_path, data: { turbo: "false" },
class: "inline-flex items-center gap-2 px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
<% end %>
</div>
<div class="space-y-3" id="user_email_addresses">
<h3 class="text-lg font-medium text-white">Email Addresses</h3>
<p class="text-gray-300 text-sm">These are the email addresses associated with your account.</p>
<% if @user.email_addresses.any? %>
<div class="space-y-2">
<% @user.email_addresses.each do |email| %>
<div class="flex items-center gap-2 p-2 bg-gray-800 border border-gray-600 rounded">
<span class="text-gray-300 text-sm"><%= email.email %></span>
<span class="text-xs px-2 py-1 bg-gray-700 text-gray-200 rounded">
<%= email.source&.humanize || "Unknown" %>
</span>
</div>
<% end %>
</div>
<% else %>
<p class="text-gray-400 text-sm">No email addresses found.</p>
<% end %>
<%= form_tag add_email_auth_path, data: { turbo: false }, class: "space-y-2" do %>
<%= email_field_tag :email, nil,
placeholder: "Add another email address",
required: true,
class: "w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded text-white focus:border-primary focus:ring-1 focus:ring-primary text-sm" %>
<%= submit_tag "Add Email", class: "w-full px-3 py-2 bg-primary hover:bg-primary/80 text-white text-sm font-medium rounded transition-colors duration-200" %>
<% end %>
</div>
</div>
</div>
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-red-600/10 rounded">
<span class="text-2xl">📊</span>
</div>
<h2 class="text-xl font-semibold text-white" id="user_stats_badges">Stats Badges</h2>
</div>
<div class="space-y-6">
<div>
<h3 class="text-lg font-medium text-white mb-2">General Stats Badge</h3>
<p class="text-gray-300 text-sm mb-4">Show your coding stats on your GitHub profile with beautiful badges.</p>
<div class="space-y-3">
<div>
<label class="block text-sm font-medium text-gray-200 mb-2">Theme</label>
<select name="theme" id="theme-select" onchange="up1(this.value)"
class="w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded text-white focus:border-primary focus:ring-1 focus:ring-primary">
<% GithubReadmeStats.themes.each do |theme| %>
<option value="<%= theme %>"><%= theme.humanize %></option>
<% end %>
</select>
</div>
<% gh_badge = GithubReadmeStats.new(current_user.id, "darcula") %>
<div class="p-4 bg-gray-800 border border-gray-600 rounded">
<img id="badge-preview" src="<%= gh_badge.generate_badge_url %>" data-url="<%= gh_badge.generate_badge_url %>" class="mb-3 rounded">
<pre id="badge-url" class="text-xs text-gray-300 bg-gray-900 p-2 rounded overflow-x-auto"><%= gh_badge.generate_badge_url %></pre>
</div>
</div>
</div>
<% if @projects.any? && @user.slack_uid.present? %>
<div class="border-t border-gray-700 pt-4">
<h3 class="text-lg font-medium text-white mb-2">Project Stats Badge</h3>
<div class="space-y-2">
<label class="block text-sm font-medium text-gray-200">Project</label>
<select name="project" id="project-select" onchange="up2(this.value)"
class="w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded text-white focus:border-primary focus:ring-1 focus:ring-primary">
<% @projects.each do |project| %>
<option value="<%= project %>"><%= project %></option>
<% end %>
</select>
<div class="mt-3 p-4 bg-gray-800 border border-gray-600 rounded">
<img id="project-badge-preview" src="<%= @work_time_stats_url %>" class="mb-3 rounded">
<pre id="project-badge-url" class="text-xs text-gray-300 bg-gray-900 p-2 rounded overflow-x-auto"><%= @work_time_stats_url %></pre>
</div>
</div>
</div>
<% end %>
</div>
<script>
function up1(theme) {
const preview = document.getElementById('badge-preview');
const url = document.getElementById('badge-url');
const baseUrl = preview.dataset.url.replace(/theme=[^&]*/, '');
const newUrl = baseUrl + (baseUrl.includes('?') ? '&' : '?') + 'theme=' + theme;
preview.src = newUrl;
url.textContent = newUrl;
}
function up2(project) {
const preview = document.getElementById('project-badge-preview');
const url = document.getElementById('project-badge-url');
const baseUrl = '<%= @work_time_stats_url.gsub(@projects.first || 'example', '') %>';
const newUrl = baseUrl + project;
preview.src = newUrl;
url.textContent = newUrl;
}
</script>
</div>
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200 space-y-6">
<div>
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-red-600/10 rounded">
<span class="text-2xl">📄</span>
</div>
<h2 class="text-xl font-semibold text-white" id="user_config_file">Config File</h2>
</div>
<p class="text-gray-300 text-sm mb-4">Your Wakatime configuration file for tracking coding time.</p>
<div class="bg-gray-800 border border-gray-600 rounded p-4 overflow-x-auto">
<%= render "wakatime_config_display" %>
</div>
<p class="text-xs text-gray-400 mt-2">
This configuration file is automatically generated and updated when you make changes to your settings.
</p>
</div>
<div class="border-t border-gray-700 pt-6">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-red-600/10 rounded">
<span class="text-2xl">🚚</span>
</div>
<h2 class="text-xl font-semibold text-white" id="user_migration_assistant">Migration Assistant</h2>
</div>
<p class="text-gray-300 text-sm mb-4">This will migrate your heartbeats from waka.hackclub.com to this platform.</p>
<%= button_to "Migrate heartbeats", my_settings_migrate_heartbeats_path, method: :post,
class: "w-full px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
<% if @heartbeats_migration_jobs.any? %>
<div class="mt-4 space-y-2">
<h3 class="text-sm font-medium text-white">Migration Status</h3>
<% @heartbeats_migration_jobs.each do |job| %>
<div class="p-2 bg-gray-800 border border-gray-600 rounded text-xs text-gray-300">
Job ID: <%= job.id %> - Status: <%= job.status %>
</div>
<% end %>
</div>
<% end %>
</div>
</div>
<div class="border border-primary rounded-xl p-6 hover:bg-gray-800/50 transition-all duration-200 md:col-span-2">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-red-600/10 rounded">
<span class="text-2xl">📝</span>
</div>
<h2 class="text-xl font-semibold text-white" id="user_markscribe">Markscribe Templates</h2>
</div>
<p class="text-gray-300 text-sm mb-4">Use markscribe to create beautiful GitHub profile READMEs with your coding stats.</p>
<div class="grid grid-cols-1 lg:grid-cols-2 gap-6">
<div>
<div class="p-4 bg-gray-800 border border-gray-600 rounded mb-4 overflow-x-auto">
<pre class="text-sm text-gray-200 whitespace-pre-wrap break-all"><code>{{ wakatimeDoubleCategoryBar "💾 Languages:" wakatimeData.Languages "💼 Projects:" wakatimeData.Projects 5 }}</code></pre>
</div>
<p class="text-gray-300 text-sm mb-2">Add this to your GitHub profile README template to display your top languages and projects.</p>
<p class="text-xs text-gray-400">See the <a href="https://github.com/taciturnaxolotl/markscribe#your-wakatime-languages-formated-as-a-bar" target="_blank" class="text-primary hover:text-primary/80 underline">markscribe documentation</a> for more template options.</p>
</div>
<div>
<img src="https://cdn.fluff.pw/slackcdn/524e293aa09bc5f9115c0c29c18fb4bc.png"
alt="Example of markscribe output showing coding language and project statistics"
class="w-full rounded border border-gray-600"/>
</div>
</div>
</div>
<% admin_tool do %>
<div class="p-6 md:col-span-2">
<div class="flex items-center gap-3 mb-4">
<div class="p-2 bg-red-600/10 rounded">
<span class="text-2xl">🔧</span>
</div>
<h2 class="text-xl font-semibold text-white">WakaTime Mirrors</h2>
</div>
<% if current_user.wakatime_mirrors.any? %>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-4">
<% current_user.wakatime_mirrors.each do |mirror| %>
<div class="p-4 bg-gray-800 border border-gray-600 rounded">
<h3 class="text-white font-medium"><%= mirror.name %></h3>
<p class="text-gray-400 text-sm"><%= mirror.endpoint_url %></p>
</div>
<% end %>
</div>
<% end %>
<%= form_with(model: [current_user, WakatimeMirror.new], local: true, class: "space-y-4") do |f| %>
<div class="grid grid-cols-1 md:grid-cols-2 gap-4">
<div>
<%= f.label :name, class: "block text-sm font-medium text-gray-200 mb-2" %>
<%= f.text_field :name, class: "w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded text-white focus:border-primary focus:ring-1 focus:ring-primary" %>
</div>
<div>
<%= f.label :endpoint_url, class: "block text-sm font-medium text-gray-200 mb-2" %>
<%= f.url_field :endpoint_url, class: "w-full px-3 py-2 bg-gray-800 border border-gray-600 rounded text-white focus:border-primary focus:ring-1 focus:ring-primary" %>
</div>
</div>
<%= f.submit "Add Mirror", class: "px-4 py-2 bg-primary text-white font-medium rounded transition-colors duration-200" %>
<% end %>
</div>
<% end %>
</div>
</div>