mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 01:08:56 +00:00
388 lines
24 KiB
PHP
388 lines
24 KiB
PHP
@extends('layouts.main')
|
|
|
|
@section('content')
|
|
<div class="max-w-4xl mx-auto">
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-sm">
|
|
<!-- Header -->
|
|
<div class="px-6 py-4 border-b border-gray-200">
|
|
<h1 class="text-2xl font-bold text-gray-800">Edit Profile</h1>
|
|
<p class="text-gray-600 dark:text-gray-400 mt-1">Update your account settings and preferences</p>
|
|
</div>
|
|
|
|
<!-- Messages -->
|
|
@if(session('success'))
|
|
<div class="mx-6 mt-6 p-4 bg-green-50 border-l-4 border-green-500 text-green-800 rounded">
|
|
<i class="fas fa-check-circle mr-2"></i>{{ session('success') }}
|
|
</div>
|
|
@endif
|
|
|
|
@if($success_2fa)
|
|
<div class="mx-6 mt-6 p-4 bg-green-50 border-l-4 border-green-500 text-green-800 rounded">
|
|
<i class="fas fa-check-circle mr-2"></i>{{ $success_2fa }}
|
|
</div>
|
|
@endif
|
|
|
|
@if($error || $error_2fa)
|
|
<div class="mx-6 mt-6 p-4 bg-red-50 border-l-4 border-red-500 text-red-800 rounded">
|
|
<i class="fas fa-exclamation-circle mr-2"></i>{{ $error ?: $error_2fa }}
|
|
</div>
|
|
@endif
|
|
|
|
<!-- Form -->
|
|
<form method="POST" action="{{ route('profileedit') }}" class="p-6 space-y-6">
|
|
@csrf
|
|
<input type="hidden" name="action" value="submit">
|
|
|
|
<!-- Email -->
|
|
<div>
|
|
<label for="email" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Email Address</label>
|
|
<input type="email" name="email" id="email" value="{{ old('email', $user->email) }}"
|
|
class="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 @error('email') border-red-500 @enderror">
|
|
@error('email')
|
|
<p class="mt-2 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Password -->
|
|
<div>
|
|
<label for="password" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">New Password (leave blank to keep current)</label>
|
|
<input type="password" name="password" id="password"
|
|
class="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 @error('password') border-red-500 @enderror">
|
|
<p class="mt-1 text-xs text-gray-500">Must contain at least 8 characters, including uppercase, lowercase, numbers and special characters</p>
|
|
@error('password')
|
|
<p class="mt-2 text-sm text-red-600">{{ $message }}</p>
|
|
@enderror
|
|
</div>
|
|
|
|
<!-- Confirm Password -->
|
|
<div>
|
|
<label for="password_confirmation" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">Confirm Password</label>
|
|
<input type="password" name="password_confirmation" id="password_confirmation"
|
|
class="w-full px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500">
|
|
</div>
|
|
|
|
<!-- Theme Preference -->
|
|
<div class="border-t border-gray-200 dark:border-gray-700 pt-6">
|
|
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4">
|
|
<i class="fas fa-palette mr-2 text-blue-600 dark:text-blue-400"></i>Theme Preference
|
|
</h3>
|
|
<div class="space-y-3">
|
|
<label class="flex items-center p-4 border-2 rounded-lg cursor-pointer transition {{ ($user->theme_preference ?? 'light') === 'light' ? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20' : 'border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-700' }}">
|
|
<input type="radio" name="theme_preference" value="light" {{ ($user->theme_preference ?? 'light') === 'light' ? 'checked' : '' }}
|
|
class="w-4 h-4 text-blue-600 focus:ring-blue-500 border-gray-300">
|
|
<div class="ml-3 flex-1">
|
|
<div class="flex items-center">
|
|
<i class="fas fa-sun text-yellow-500 text-xl mr-3"></i>
|
|
<div>
|
|
<span class="block text-sm font-medium text-gray-900 dark:text-gray-100">Light Mode</span>
|
|
<span class="block text-xs text-gray-600 dark:text-gray-400">Bright and clean interface</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</label>
|
|
<label class="flex items-center p-4 border-2 rounded-lg cursor-pointer transition {{ ($user->theme_preference ?? 'light') === 'dark' ? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20' : 'border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-700' }}">
|
|
<input type="radio" name="theme_preference" value="dark" {{ ($user->theme_preference ?? 'light') === 'dark' ? 'checked' : '' }}
|
|
class="w-4 h-4 text-blue-600 focus:ring-blue-500 border-gray-300">
|
|
<div class="ml-3 flex-1">
|
|
<div class="flex items-center">
|
|
<i class="fas fa-moon text-indigo-500 text-xl mr-3"></i>
|
|
<div>
|
|
<span class="block text-sm font-medium text-gray-900 dark:text-gray-100">Dark Mode</span>
|
|
<span class="block text-xs text-gray-600 dark:text-gray-400">Easy on the eyes, especially at night</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</label>
|
|
<label class="flex items-center p-4 border-2 rounded-lg cursor-pointer transition {{ ($user->theme_preference ?? 'light') === 'system' ? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20' : 'border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-700' }}">
|
|
<input type="radio" name="theme_preference" value="system" {{ ($user->theme_preference ?? 'light') === 'system' ? 'checked' : '' }}
|
|
class="w-4 h-4 text-blue-600 focus:ring-blue-500 border-gray-300">
|
|
<div class="ml-3 flex-1">
|
|
<div class="flex items-center">
|
|
<i class="fas fa-desktop text-blue-500 text-xl mr-3"></i>
|
|
<div>
|
|
<span class="block text-sm font-medium text-gray-900 dark:text-gray-100">System (Auto)</span>
|
|
<span class="block text-xs text-gray-600 dark:text-gray-400">Match your operating system's theme</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</label>
|
|
</div>
|
|
<p class="mt-3 text-xs text-gray-500 dark:text-gray-400">
|
|
<i class="fas fa-info-circle mr-1"></i>Your theme preference will be applied across all devices and browsers when you're logged in.
|
|
</p>
|
|
</div>
|
|
|
|
<!-- View Preferences -->
|
|
<div class="border-t border-gray-200 dark:border-gray-700 pt-6">
|
|
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4">Cover View Preferences</h3>
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="movieview" value="1" {{ $user->movieview ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">Movie Covers</span>
|
|
</label>
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="musicview" value="1" {{ $user->musicview ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">Music Covers</span>
|
|
</label>
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="consoleview" value="1" {{ $user->consoleview ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">Console Covers</span>
|
|
</label>
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="gameview" value="1" {{ $user->gameview ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">Game Covers</span>
|
|
</label>
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="bookview" value="1" {{ $user->bookview ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">Book Covers</span>
|
|
</label>
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="xxxview" value="1" {{ $user->xxxview ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">XXX Covers</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Category Permissions -->
|
|
<div class="border-t border-gray-200 dark:border-gray-700 pt-6">
|
|
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4">Category Permissions</h3>
|
|
<div class="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="viewmovies" value="1" {{ $user->movieview ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">Movies</span>
|
|
</label>
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="viewtv" value="1" {{ $user->can('view tv') ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">TV</span>
|
|
</label>
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="viewaudio" value="1" {{ $user->musicview ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">Audio</span>
|
|
</label>
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="viewpc" value="1" {{ $user->gameview ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">PC</span>
|
|
</label>
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="viewconsole" value="1" {{ $user->consoleview ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">Console</span>
|
|
</label>
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="viewbooks" value="1" {{ $user->bookview ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">Books</span>
|
|
</label>
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="viewadult" value="1" {{ $user->xxxview ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">Adult</span>
|
|
</label>
|
|
<label class="flex items-center">
|
|
<input type="checkbox" name="viewother" value="1" {{ $user->can('view other') ? 'checked' : '' }}
|
|
class="rounded border-gray-300 dark:border-gray-600 text-blue-600 dark:text-blue-400 focus:ring-blue-500 mr-2">
|
|
<span class="text-sm text-gray-700">Other</span>
|
|
</label>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Actions -->
|
|
<div class="border-t border-gray-200 dark:border-gray-700 pt-6 flex items-center justify-between">
|
|
<a href="{{ route('profile') }}" class="px-6 py-2 text-gray-700 dark:text-gray-300 bg-gray-200 dark:bg-gray-700 rounded-lg hover:bg-gray-300 transition">
|
|
Cancel
|
|
</a>
|
|
<div class="flex space-x-2">
|
|
<a href="{{ route('profileedit', ['action' => 'newapikey']) }}"
|
|
class="px-6 py-2 text-blue-700 bg-blue-100 rounded-lg hover:bg-blue-200 transition"
|
|
onclick="return confirm('Are you sure you want to generate a new API key?')">
|
|
<i class="fas fa-key mr-2"></i>New API Key
|
|
</a>
|
|
<button type="submit" class="px-6 py-2 bg-blue-600 dark:bg-blue-700 text-white rounded-lg hover:bg-blue-700 dark:hover:bg-blue-800 transition">
|
|
<i class="fas fa-save mr-2"></i>Save Changes
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</form>
|
|
|
|
<!-- 2FA Section (Outside main form) -->
|
|
<div class="p-6 border-t border-gray-200">
|
|
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 mb-4">
|
|
<i class="fas fa-shield-alt mr-2 text-blue-600"></i>Two-Factor Authentication (2FA)
|
|
</h3>
|
|
|
|
@if($user->passwordSecurity()->exists() && $user->passwordSecurity->google2fa_enable)
|
|
<!-- 2FA is Enabled -->
|
|
<div class="bg-green-50 border-l-4 border-green-500 rounded-lg p-4">
|
|
<div class="flex items-start">
|
|
<i class="fas fa-check-circle text-green-600 text-xl mr-3 mt-1"></i>
|
|
<div class="flex-1">
|
|
<h4 class="text-green-800 font-semibold mb-1">Two-Factor Authentication is Active</h4>
|
|
<p class="text-green-700 text-sm mb-4">Your account is protected with an additional layer of security. You'll need your authenticator app to log in.</p>
|
|
|
|
<form method="POST" action="{{ route('profileedit.disable2fa') }}" class="inline">
|
|
@csrf
|
|
<button type="submit"
|
|
class="px-4 py-2 bg-red-600 dark:bg-red-700 text-white text-sm rounded-lg hover:bg-red-700 dark:hover:bg-red-800 transition"
|
|
onclick="return confirm('Are you sure you want to disable two-factor authentication? This will make your account less secure.')">
|
|
<i class="fas fa-times-circle mr-2"></i>Disable 2FA
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@elseif($user->passwordSecurity()->exists() && !$user->passwordSecurity->google2fa_enable)
|
|
<!-- 2FA Setup Started but Not Enabled -->
|
|
<div class="bg-blue-50 border-l-4 border-blue-500 rounded-lg p-4">
|
|
<div class="flex items-start">
|
|
<i class="fas fa-info-circle text-blue-600 dark:text-blue-400 text-xl mr-3 mt-1"></i>
|
|
<div class="flex-1">
|
|
<h4 class="text-blue-800 font-semibold mb-2">Complete Your 2FA Setup</h4>
|
|
<p class="text-blue-700 text-sm mb-4">Follow these steps to enable two-factor authentication:</p>
|
|
|
|
<ol class="list-decimal list-inside space-y-2 text-sm text-blue-700 mb-4">
|
|
<li>Install an authenticator app (Google Authenticator, Authy, or similar)</li>
|
|
<li>Scan the QR code below with your authenticator app</li>
|
|
<li>Enter the 6-digit code from your app to verify</li>
|
|
</ol>
|
|
|
|
<div class="bg-white dark:bg-gray-800 rounded-lg p-4 mb-4 flex justify-center">
|
|
<img src="{{ $google2fa_url }}" alt="2FA QR Code">
|
|
</div>
|
|
|
|
<p class="text-xs text-blue-600 dark:text-blue-400 mb-4">
|
|
<strong>Secret Key (manual entry):</strong>
|
|
<code class="bg-white dark:bg-gray-800 px-2 py-1 rounded">{{ $user->passwordSecurity->google2fa_secret }}</code>
|
|
</p>
|
|
|
|
|
|
<form method="POST" action="{{ route('enable2fa') }}" class="space-y-3">
|
|
@csrf
|
|
<div>
|
|
<label for="one_time_password" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
|
Enter Verification Code
|
|
</label>
|
|
<input type="text"
|
|
id="one_time_password"
|
|
name="one_time_password"
|
|
placeholder="Enter 6-digit code"
|
|
maxlength="6"
|
|
required
|
|
class="w-full md:w-64 px-4 py-2 border border-gray-300 dark:border-gray-600 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-center text-lg tracking-widest">
|
|
</div>
|
|
<div class="flex gap-2">
|
|
<button type="submit" class="px-4 py-2 bg-green-600 dark:bg-green-700 text-white text-sm rounded-lg hover:bg-green-700 dark:hover:bg-green-800 transition">
|
|
<i class="fas fa-check mr-2"></i>Verify and Enable 2FA
|
|
</button>
|
|
</div>
|
|
</form>
|
|
|
|
<form method="POST" action="{{ route('profileedit.cancel2fa') }}" class="mt-2">
|
|
@csrf
|
|
<button type="submit" class="px-4 py-2 bg-gray-600 text-white text-sm rounded-lg hover:bg-gray-700 transition">
|
|
<i class="fas fa-times mr-2"></i>Cancel Setup
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@else
|
|
<!-- 2FA Not Set Up -->
|
|
<div class="bg-yellow-50 border-l-4 border-yellow-500 rounded-lg p-4">
|
|
<div class="flex items-start">
|
|
<i class="fas fa-exclamation-triangle text-yellow-600 text-xl mr-3 mt-1"></i>
|
|
<div class="flex-1">
|
|
<h4 class="text-yellow-800 font-semibold mb-1">Two-Factor Authentication is Disabled</h4>
|
|
<p class="text-yellow-700 text-sm mb-4">Add an extra layer of security to your account by enabling two-factor authentication.</p>
|
|
|
|
<form method="POST" action="{{ route('generate2faSecret') }}">
|
|
@csrf
|
|
<input type="hidden" name="from_profile" value="1">
|
|
<button type="submit" class="px-4 py-2 bg-blue-600 dark:bg-blue-700 text-white text-sm rounded-lg hover:bg-blue-700 dark:hover:bg-blue-800 transition">
|
|
<i class="fas fa-shield-alt mr-2"></i>Enable Two-Factor Authentication
|
|
</button>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endif
|
|
|
|
<div class="mt-4 p-3 bg-gray-50 dark:bg-gray-900 rounded-lg">
|
|
<p class="text-xs text-gray-600">
|
|
<i class="fas fa-info-circle mr-1"></i>
|
|
<strong>What is 2FA?</strong> Two-Factor Authentication adds an extra layer of security by requiring both your password and a code from your phone to log in.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
@endsection
|
|
|
|
@push('scripts')
|
|
<script>
|
|
// Theme preference instant preview
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const themeRadios = document.querySelectorAll('input[name="theme_preference"]');
|
|
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
|
|
function applyTheme(themeValue) {
|
|
const html = document.documentElement;
|
|
|
|
if (themeValue === 'system') {
|
|
// Use OS preference
|
|
if (mediaQuery.matches) {
|
|
html.classList.add('dark');
|
|
} else {
|
|
html.classList.remove('dark');
|
|
}
|
|
} else if (themeValue === 'dark') {
|
|
html.classList.add('dark');
|
|
} else {
|
|
html.classList.remove('dark');
|
|
}
|
|
}
|
|
|
|
themeRadios.forEach(radio => {
|
|
radio.addEventListener('change', function() {
|
|
applyTheme(this.value);
|
|
updateThemeSelection();
|
|
});
|
|
});
|
|
|
|
function updateThemeSelection() {
|
|
const selectedValue = document.querySelector('input[name="theme_preference"]:checked').value;
|
|
document.querySelectorAll('input[name="theme_preference"]').forEach((radio) => {
|
|
const label = radio.closest('label');
|
|
const isSelected = radio.value === selectedValue;
|
|
|
|
if (isSelected) {
|
|
label.classList.remove('border-gray-300', 'dark:border-gray-600', 'bg-gray-50', 'dark:bg-gray-700');
|
|
label.classList.add('border-blue-500', 'bg-blue-50', 'dark:bg-blue-900/20');
|
|
} else {
|
|
label.classList.remove('border-blue-500', 'bg-blue-50', 'dark:bg-blue-900/20');
|
|
label.classList.add('border-gray-300', 'dark:border-gray-600', 'bg-gray-50', 'dark:bg-gray-700');
|
|
}
|
|
});
|
|
}
|
|
|
|
// Listen for OS theme changes when system mode is selected
|
|
mediaQuery.addEventListener('change', (e) => {
|
|
const selectedTheme = document.querySelector('input[name="theme_preference"]:checked').value;
|
|
if (selectedTheme === 'system') {
|
|
applyTheme('system');
|
|
}
|
|
});
|
|
});
|
|
</script>
|
|
@endpush
|
|
|