feat(settings): add Billing, Danger Zone, Domains DNS, Notification, Player, and Security settings pages

- Implemented Billing page with wallet balance, current plan, usage stats, available plans, and payment history.
- Created Danger Zone page for account deletion and data clearing actions with confirmation prompts.
- Developed Domains DNS page for managing whitelisted domains for iframe embedding, including add and remove functionality.
- Added Notification Settings page to configure email, push, marketing, and Telegram notifications.
- Introduced Player Settings page to customize video player behavior such as autoplay, loop, and controls visibility.
- Established Security and Connected Accounts page for managing user profile, two-factor authentication, and connected accounts.
This commit is contained in:
2026-03-01 22:49:30 +07:00
parent c6924afe5b
commit cd9aab8979
65 changed files with 3150 additions and 1133 deletions

View File

@@ -0,0 +1,262 @@
<script setup lang="ts">
import { useAuthStore } from '@/stores/auth';
import { useToast } from 'primevue/usetoast';
import { ref } from 'vue';
import ProfileInformationCard from '../components/ProfileInformationCard.vue';
import SecuritySettingsCard from '../components/SecuritySettingsCard.vue';
import ConnectedAccountsCard from '../components/ConnectedAccountsCard.vue';
const auth = useAuthStore();
const toast = useToast();
// Form state
const editing = ref(false);
const username = ref('');
const email = ref('');
const saving = ref(false);
// 2FA state
const twoFactorEnabled = ref(false);
const twoFactorDialogVisible = ref(false);
// Connected accounts state
const emailConnected = ref(true);
const telegramConnected = ref(false);
const telegramUsername = ref('');
// Change password state
const changePasswordDialogVisible = ref(false);
const currentPassword = ref('');
const newPassword = ref('');
const confirmPassword = ref('');
const changePasswordLoading = ref(false);
const changePasswordError = ref('');
// Initialize form values
const initForm = () => {
username.value = auth.user?.username || '';
email.value = auth.user?.email || '';
emailConnected.value = !!auth.user?.email;
};
// Start editing
const startEdit = () => {
initForm();
editing.value = true;
};
// Cancel edit
const cancelEdit = () => {
editing.value = false;
};
// Save profile
const saveProfile = async () => {
saving.value = true;
try {
await auth.updateProfile({ username: username.value, email: email.value });
toast.add({
severity: 'success',
summary: 'Profile Updated',
detail: 'Your profile has been updated successfully.',
life: 3000
});
editing.value = false;
} catch (e: any) {
toast.add({
severity: 'error',
summary: 'Update Failed',
detail: e.message || 'Failed to update profile.',
life: 5000
});
} finally {
saving.value = false;
}
};
// Change password handler
const openChangePassword = () => {
changePasswordDialogVisible.value = true;
changePasswordError.value = '';
currentPassword.value = '';
newPassword.value = '';
confirmPassword.value = '';
};
const changePassword = async () => {
changePasswordError.value = '';
if (newPassword.value !== confirmPassword.value) {
changePasswordError.value = 'Passwords do not match';
return;
}
if (newPassword.value.length < 6) {
changePasswordError.value = 'Password must be at least 6 characters';
return;
}
changePasswordLoading.value = true;
try {
await auth.changePassword(currentPassword.value, newPassword.value);
changePasswordDialogVisible.value = false;
currentPassword.value = '';
newPassword.value = '';
confirmPassword.value = '';
toast.add({
severity: 'success',
summary: 'Password Changed',
detail: 'Your password has been changed successfully.',
life: 3000
});
} catch (e: any) {
changePasswordError.value = e.message || 'Failed to change password';
} finally {
changePasswordLoading.value = false;
}
};
// Toggle 2FA
const toggleTwoFactor = async () => {
if (!twoFactorEnabled.value) {
// Enable 2FA - generate secret and QR code
try {
await new Promise(resolve => setTimeout(resolve, 500));
twoFactorDialogVisible.value = true;
} catch (e) {
toast.add({
severity: 'error',
summary: 'Enable 2FA Failed',
detail: 'Failed to enable two-factor authentication.',
life: 5000
});
twoFactorEnabled.value = false;
}
} else {
// Disable 2FA
try {
await new Promise(resolve => setTimeout(resolve, 500));
toast.add({
severity: 'success',
summary: '2FA Disabled',
detail: 'Two-factor authentication has been disabled.',
life: 3000
});
} catch (e) {
toast.add({
severity: 'error',
summary: 'Disable 2FA Failed',
detail: 'Failed to disable two-factor authentication.',
life: 5000
});
twoFactorEnabled.value = true;
}
}
};
// Confirm 2FA setup
const confirmTwoFactor = async () => {
try {
await new Promise(resolve => setTimeout(resolve, 500));
twoFactorEnabled.value = true;
toast.add({
severity: 'success',
summary: '2FA Enabled',
detail: 'Two-factor authentication has been enabled successfully.',
life: 3000
});
} catch (e) {
toast.add({
severity: 'error',
summary: 'Enable 2FA Failed',
detail: 'Invalid verification code. Please try again.',
life: 5000
});
}
};
// Connect Telegram
const connectTelegram = async () => {
try {
await new Promise(resolve => setTimeout(resolve, 1000));
telegramConnected.value = true;
telegramUsername.value = '@telegram_user';
toast.add({
severity: 'success',
summary: 'Telegram Connected',
detail: `Connected to ${telegramUsername.value}`,
life: 3000
});
} catch (e) {
toast.add({
severity: 'error',
summary: 'Connection Failed',
detail: 'Failed to connect Telegram account.',
life: 5000
});
}
};
// Disconnect Telegram
const disconnectTelegram = async () => {
try {
await new Promise(resolve => setTimeout(resolve, 500));
telegramConnected.value = false;
telegramUsername.value = '';
toast.add({
severity: 'info',
summary: 'Telegram Disconnected',
detail: 'Your Telegram account has been disconnected.',
life: 3000
});
} catch (e) {
toast.add({
severity: 'error',
summary: 'Disconnect Failed',
detail: 'Failed to disconnect Telegram account.',
life: 5000
});
}
};
</script>
<template>
<div class="space-y-6">
<SecuritySettingsCard
v-model:two-factor-enabled="twoFactorEnabled"
:change-password-error="changePasswordError"
:change-password-loading="changePasswordLoading"
:current-password="currentPassword"
:new-password="newPassword"
:confirm-password="confirmPassword"
@toggle-2fa="toggleTwoFactor"
@change-password="openChangePassword"
@close-password-dialog="changePasswordDialogVisible = false"
@close-2fa-dialog="twoFactorDialogVisible = false"
@confirm-2fa="confirmTwoFactor"
@update:current-password="currentPassword = $event"
@update:new-password="newPassword = $event"
@update:confirm-password="confirmPassword = $event"
/>
<ConnectedAccountsCard
:dialog-visible="changePasswordDialogVisible"
@update:dialog-visible="changePasswordDialogVisible = $event"
:error="changePasswordError"
:loading="changePasswordLoading"
:current-password="currentPassword"
:new-password="newPassword"
:confirm-password="confirmPassword"
:email-connected="emailConnected"
:telegram-connected="telegramConnected"
:telegram-username="telegramUsername"
@close="changePasswordDialogVisible = false"
@change-password="changePassword"
@connect-telegram="connectTelegram"
@disconnect-telegram="disconnectTelegram"
@update:current-password="currentPassword = $event"
@update:new-password="newPassword = $event"
@update:confirm-password="confirmPassword = $event"
/>
</div>
</template>