jobs/src/views/Settings.vue

892 lines
23 KiB
Vue

<script setup>
import { ref, inject, watch } from 'vue';
// Get theme state from parent
const isDarkMode = inject('isDarkMode');
const toggleTheme = inject('toggleTheme');
const userSettings = ref({
account: {
name: 'Alex Johnson',
email: 'alex.johnson@example.com',
phone: '+1 (555) 123-4567',
location: 'San Francisco, CA',
},
preferences: {
darkMode: isDarkMode,
emailNotifications: true,
pushNotifications: false,
jobAlerts: true,
newsletter: false,
language: 'English',
timezone: 'Pacific Time (PT)',
},
privacy: {
profileVisibility: 'Public',
resumeVisibility: 'Connections only',
activityVisibility: 'Private',
allowRecruiters: true,
allowCompanies: true,
dataSharing: false,
},
security: {
twoFactorAuth: false,
lastPasswordChange: '3 months ago',
loginHistory: [
{ device: 'MacBook Pro', location: 'San Francisco, CA', time: 'Today, 9:45 AM' },
{ device: 'iPhone 14', location: 'San Francisco, CA', time: 'Yesterday, 6:30 PM' },
{ device: 'Windows PC', location: 'San Jose, CA', time: '3 days ago, 2:15 PM' },
],
connectedAccounts: [
{ name: 'Google', connected: true },
{ name: 'LinkedIn', connected: true },
{ name: 'GitHub', connected: false },
],
},
billing: {
plan: 'Professional',
nextBilling: 'May 15, 2025',
paymentMethod: 'Visa ending in 4242',
billingHistory: [
{ date: 'April 15, 2025', amount: '$19.99', status: 'Paid' },
{ date: 'March 15, 2025', amount: '$19.99', status: 'Paid' },
{ date: 'February 15, 2025', amount: '$19.99', status: 'Paid' },
],
},
});
const activeTab = ref('account');
const setActiveTab = (tab) => {
activeTab.value = tab;
};
// Watch for changes to the dark mode preference
watch(() => userSettings.value.preferences.darkMode, (newValue) => {
// Update the app's theme when the setting changes
if (newValue !== isDarkMode.value) {
toggleTheme(newValue);
}
});
// Watch for changes to the app's theme
watch(isDarkMode, (newValue) => {
// Update the setting when the app's theme changes
userSettings.value.preferences.darkMode = newValue;
});
const saveSettings = () => {
// In a real app, this would save settings to a backend
// Apply theme change if dark mode preference was changed
if (userSettings.value.preferences.darkMode !== isDarkMode.value) {
toggleTheme(userSettings.value.preferences.darkMode);
}
alert('Settings saved successfully!');
};
</script>
<template>
<div class="settings-container" :class="{ 'dark-theme': isDarkMode }">
<div class="settings-header">
<h2>Account Settings</h2>
<p>Manage your account settings and preferences</p>
</div>
<div class="settings-content">
<div class="settings-sidebar">
<ul class="settings-nav">
<li>
<button
@click="setActiveTab('account')"
:class="{ active: activeTab === 'account' }"
>
Account
</button>
</li>
<li>
<button
@click="setActiveTab('preferences')"
:class="{ active: activeTab === 'preferences' }"
>
Preferences
</button>
</li>
<li>
<button
@click="setActiveTab('privacy')"
:class="{ active: activeTab === 'privacy' }"
>
Privacy
</button>
</li>
<li>
<button
@click="setActiveTab('security')"
:class="{ active: activeTab === 'security' }"
>
Security
</button>
</li>
<li>
<button
@click="setActiveTab('billing')"
:class="{ active: activeTab === 'billing' }"
>
Billing
</button>
</li>
</ul>
</div>
<div class="settings-main">
<!-- Account Settings -->
<div v-if="activeTab === 'account'" class="settings-panel">
<h3>Personal Information</h3>
<div class="form-group">
<label for="name">Full Name</label>
<input
type="text"
id="name"
v-model="userSettings.account.name"
class="form-control"
/>
</div>
<div class="form-group">
<label for="email">Email Address</label>
<input
type="email"
id="email"
v-model="userSettings.account.email"
class="form-control"
/>
</div>
<div class="form-group">
<label for="phone">Phone Number</label>
<input
type="tel"
id="phone"
v-model="userSettings.account.phone"
class="form-control"
/>
</div>
<div class="form-group">
<label for="location">Location</label>
<input
type="text"
id="location"
v-model="userSettings.account.location"
class="form-control"
/>
</div>
<div class="form-actions">
<button @click="saveSettings" class="btn-save">Save Changes</button>
</div>
</div>
<!-- Preferences Settings -->
<div v-if="activeTab === 'preferences'" class="settings-panel">
<h3>User Preferences</h3>
<div class="form-group toggle">
<label>
<span>Dark Mode</span>
<div class="toggle-switch">
<input
type="checkbox"
v-model="userSettings.preferences.darkMode"
/>
<span class="toggle-slider"></span>
</div>
</label>
</div>
<div class="form-group toggle">
<label>
<span>Email Notifications</span>
<div class="toggle-switch">
<input
type="checkbox"
v-model="userSettings.preferences.emailNotifications"
/>
<span class="toggle-slider"></span>
</div>
</label>
</div>
<div class="form-group toggle">
<label>
<span>Push Notifications</span>
<div class="toggle-switch">
<input
type="checkbox"
v-model="userSettings.preferences.pushNotifications"
/>
<span class="toggle-slider"></span>
</div>
</label>
</div>
<div class="form-group toggle">
<label>
<span>Job Alerts</span>
<div class="toggle-switch">
<input
type="checkbox"
v-model="userSettings.preferences.jobAlerts"
/>
<span class="toggle-slider"></span>
</div>
</label>
</div>
<div class="form-group toggle">
<label>
<span>Newsletter</span>
<div class="toggle-switch">
<input
type="checkbox"
v-model="userSettings.preferences.newsletter"
/>
<span class="toggle-slider"></span>
</div>
</label>
</div>
<div class="form-group">
<label for="language">Language</label>
<select id="language" v-model="userSettings.preferences.language" class="form-control">
<option>English</option>
<option>Spanish</option>
<option>French</option>
<option>German</option>
<option>Chinese</option>
</select>
</div>
<div class="form-group">
<label for="timezone">Timezone</label>
<select id="timezone" v-model="userSettings.preferences.timezone" class="form-control">
<option>Pacific Time (PT)</option>
<option>Mountain Time (MT)</option>
<option>Central Time (CT)</option>
<option>Eastern Time (ET)</option>
<option>Greenwich Mean Time (GMT)</option>
</select>
</div>
<div class="form-actions">
<button @click="saveSettings" class="btn-save">Save Changes</button>
</div>
</div>
<!-- Privacy Settings -->
<div v-if="activeTab === 'privacy'" class="settings-panel">
<h3>Privacy Settings</h3>
<div class="form-group">
<label for="profileVisibility">Profile Visibility</label>
<select id="profileVisibility" v-model="userSettings.privacy.profileVisibility" class="form-control">
<option>Public</option>
<option>Connections only</option>
<option>Private</option>
</select>
</div>
<div class="form-group">
<label for="resumeVisibility">Resume Visibility</label>
<select id="resumeVisibility" v-model="userSettings.privacy.resumeVisibility" class="form-control">
<option>Public</option>
<option>Connections only</option>
<option>Private</option>
</select>
</div>
<div class="form-group">
<label for="activityVisibility">Activity Visibility</label>
<select id="activityVisibility" v-model="userSettings.privacy.activityVisibility" class="form-control">
<option>Public</option>
<option>Connections only</option>
<option>Private</option>
</select>
</div>
<div class="form-group toggle">
<label>
<span>Allow Recruiters to Contact Me</span>
<div class="toggle-switch">
<input
type="checkbox"
v-model="userSettings.privacy.allowRecruiters"
/>
<span class="toggle-slider"></span>
</div>
</label>
</div>
<div class="form-group toggle">
<label>
<span>Allow Companies to View My Profile</span>
<div class="toggle-switch">
<input
type="checkbox"
v-model="userSettings.privacy.allowCompanies"
/>
<span class="toggle-slider"></span>
</div>
</label>
</div>
<div class="form-group toggle">
<label>
<span>Data Sharing with Partners</span>
<div class="toggle-switch">
<input
type="checkbox"
v-model="userSettings.privacy.dataSharing"
/>
<span class="toggle-slider"></span>
</div>
</label>
</div>
<div class="form-actions">
<button @click="saveSettings" class="btn-save">Save Changes</button>
</div>
</div>
<!-- Security Settings -->
<div v-if="activeTab === 'security'" class="settings-panel">
<h3>Security Settings</h3>
<div class="form-group toggle">
<label>
<span>Two-Factor Authentication</span>
<div class="toggle-switch">
<input
type="checkbox"
v-model="userSettings.security.twoFactorAuth"
/>
<span class="toggle-slider"></span>
</div>
</label>
</div>
<div class="form-group">
<label>Password</label>
<div class="password-info">
<span>Last changed {{ userSettings.security.lastPasswordChange }}</span>
<button class="btn-link">Change Password</button>
</div>
</div>
<h4>Login History</h4>
<div class="login-history">
<div v-for="(login, index) in userSettings.security.loginHistory" :key="index" class="login-item">
<div class="login-device">{{ login.device }}</div>
<div class="login-details">
<div>{{ login.location }}</div>
<div class="login-time">{{ login.time }}</div>
</div>
</div>
</div>
<h4>Connected Accounts</h4>
<div class="connected-accounts">
<div v-for="(account, index) in userSettings.security.connectedAccounts" :key="index" class="account-item">
<div class="account-name">{{ account.name }}</div>
<button class="btn-link">
{{ account.connected ? 'Disconnect' : 'Connect' }}
</button>
</div>
</div>
<div class="form-actions">
<button @click="saveSettings" class="btn-save">Save Changes</button>
</div>
</div>
<!-- Billing Settings -->
<div v-if="activeTab === 'billing'" class="settings-panel">
<h3>Billing Information</h3>
<div class="billing-summary">
<div class="billing-plan">
<h4>Current Plan</h4>
<div class="plan-details">
<div class="plan-name">{{ userSettings.billing.plan }}</div>
<div class="plan-billing">Next billing: {{ userSettings.billing.nextBilling }}</div>
</div>
<button class="btn-outline">Change Plan</button>
</div>
<div class="payment-method">
<h4>Payment Method</h4>
<div class="payment-details">
<div class="card-info">{{ userSettings.billing.paymentMethod }}</div>
</div>
<button class="btn-outline">Update Payment</button>
</div>
</div>
<h4>Billing History</h4>
<div class="billing-history">
<table class="billing-table">
<thead>
<tr>
<th>Date</th>
<th>Amount</th>
<th>Status</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<tr v-for="(bill, index) in userSettings.billing.billingHistory" :key="index">
<td>{{ bill.date }}</td>
<td>{{ bill.amount }}</td>
<td>
<span class="status-badge" :class="bill.status.toLowerCase()">
{{ bill.status }}
</span>
</td>
<td>
<button class="btn-link">Download</button>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.settings-container {
width: 100%;
background-color: var(--card-bg, #fff);
border-radius: 12px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.08);
overflow: hidden;
color: var(--text-color, #333);
transition: background-color 0.3s ease, color 0.3s ease, border-color 0.3s ease;
}
.settings-header {
padding: 2rem;
border-bottom: 1px solid var(--card-border, #eee);
h2 {
font-size: 1.8rem;
margin: 0 0 0.5rem;
font-weight: 600;
}
p {
color: var(--text-color-secondary, #666);
margin: 0;
}
}
.settings-content {
display: flex;
min-height: 600px;
@media (max-width: 768px) {
flex-direction: column;
}
}
.settings-sidebar {
width: 250px;
border-right: 1px solid var(--card-border, #eee);
@media (max-width: 768px) {
width: 100%;
border-right: none;
border-bottom: 1px solid var(--card-border, #eee);
}
.settings-nav {
list-style: none;
padding: 0;
margin: 0;
@media (max-width: 768px) {
display: flex;
overflow-x: auto;
white-space: nowrap;
}
li {
@media (max-width: 768px) {
flex: 1 0 auto;
}
button {
display: block;
width: 100%;
padding: 1rem 1.5rem;
text-align: left;
background: none;
border: none;
color: var(--text-color, #333);
font-size: 1rem;
cursor: pointer;
transition: background-color 0.2s, color 0.2s;
&:hover {
background-color: var(--card-bg-secondary, rgba(0, 0, 0, 0.03));
}
&.active {
background-color: var(--primary-color-light, rgba(52, 152, 219, 0.1));
color: var(--primary-color, #3498db);
border-left: 3px solid var(--primary-color, #3498db);
@media (max-width: 768px) {
border-left: none;
border-bottom: 3px solid var(--primary-color, #3498db);
}
}
}
}
}
}
.settings-main {
flex: 1;
padding: 2rem;
h3 {
margin-top: 0;
margin-bottom: 1.5rem;
font-size: 1.4rem;
font-weight: 600;
}
h4 {
margin: 2rem 0 1rem;
font-size: 1.1rem;
font-weight: 600;
}
}
.form-group {
margin-bottom: 1.5rem;
label {
display: block;
margin-bottom: 0.5rem;
font-weight: 500;
}
&.toggle {
label {
display: flex;
justify-content: space-between;
align-items: center;
cursor: pointer;
}
}
.form-control {
width: 100%;
padding: 0.75rem;
border: 1px solid var(--card-border, #ddd);
border-radius: 4px;
background-color: var(--card-bg, #fff);
color: var(--text-color, #333);
font-size: 1rem;
transition: border-color 0.2s;
&:focus {
outline: none;
border-color: var(--primary-color, #3498db);
}
}
}
.toggle-switch {
position: relative;
display: inline-block;
width: 50px;
height: 24px;
input {
opacity: 0;
width: 0;
height: 0;
&:checked + .toggle-slider {
background-color: var(--primary-color, #3498db);
&:before {
transform: translateX(26px);
}
}
}
.toggle-slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: #ccc;
transition: .4s;
border-radius: 34px;
&:before {
position: absolute;
content: "";
height: 16px;
width: 16px;
left: 4px;
bottom: 4px;
background-color: white;
transition: .4s;
border-radius: 50%;
}
}
}
.form-actions {
margin-top: 2rem;
.btn-save {
padding: 0.75rem 1.5rem;
background-color: var(--primary-color, #3498db);
color: white;
border: none;
border-radius: 4px;
font-size: 1rem;
cursor: pointer;
transition: background-color 0.2s;
&:hover {
background-color: var(--primary-color-dark, #2980b9);
}
}
}
.password-info {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.75rem;
background-color: var(--card-bg-secondary, #f9f9f9);
border-radius: 4px;
}
.btn-link {
background: none;
border: none;
color: var(--primary-color, #3498db);
cursor: pointer;
padding: 0;
font-size: 0.9rem;
&:hover {
text-decoration: underline;
}
}
.login-history {
.login-item {
display: flex;
padding: 1rem;
border-bottom: 1px solid var(--card-border, #eee);
&:last-child {
border-bottom: none;
}
.login-device {
font-weight: 500;
width: 150px;
}
.login-details {
flex: 1;
.login-time {
font-size: 0.9rem;
color: var(--text-color-secondary, #777);
margin-top: 0.25rem;
}
}
}
}
.connected-accounts {
.account-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem;
border-bottom: 1px solid var(--card-border, #eee);
&:last-child {
border-bottom: none;
}
.account-name {
font-weight: 500;
}
}
}
.billing-summary {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2rem;
margin-bottom: 2rem;
@media (max-width: 768px) {
grid-template-columns: 1fr;
}
.billing-plan, .payment-method {
padding: 1.5rem;
background-color: var(--card-bg, #fff);
border: 1px solid var(--card-border, #eee);
border-radius: 8px;
transition: background-color 0.3s ease, border-color 0.3s ease;
h4 {
margin-top: 0;
margin-bottom: 1rem;
}
.plan-details, .payment-details {
margin-bottom: 1.5rem;
.plan-name, .card-info {
font-weight: 500;
font-size: 1.1rem;
margin-bottom: 0.5rem;
}
.plan-billing {
color: var(--text-color-secondary, #777);
}
}
}
}
.btn-outline {
padding: 0.5rem 1rem;
background: none;
border: 1px solid var(--primary-color, #3498db);
color: var(--primary-color, #3498db);
border-radius: 4px;
cursor: pointer;
transition: background-color 0.2s, color 0.2s;
&:hover {
background-color: var(--primary-color, #3498db);
color: white;
}
}
.billing-table {
width: 100%;
border-collapse: collapse;
th, td {
padding: 1rem;
text-align: left;
border-bottom: 1px solid var(--card-border, #eee);
}
th {
font-weight: 600;
color: var(--text-color-secondary, #666);
}
.status-badge {
display: inline-block;
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-size: 0.85rem;
&.paid {
background-color: rgba(39, 174, 96, 0.1);
color: #27ae60;
}
&.pending {
background-color: rgba(243, 156, 18, 0.1);
color: #f39c12;
}
&.failed {
background-color: rgba(231, 76, 60, 0.1);
color: #e74c3c;
}
}
}
.dark-theme {
background-color: var(--card-bg-dark, #222);
color: var(--text-color-dark, #eee);
.settings-header {
border-bottom-color: var(--card-border-dark, #333);
}
.settings-sidebar {
border-right-color: var(--card-border-dark, #333);
@media (max-width: 768px) {
border-bottom-color: var(--card-border-dark, #333);
}
}
.form-group {
.form-control {
background-color: var(--card-bg-dark, #333);
border-color: var(--card-border-dark, #444);
color: var(--text-color-dark, #eee);
}
}
.password-info {
background-color: var(--card-bg-secondary-dark, rgba(255, 255, 255, 0.05));
}
.billing-plan,
.payment-method {
background-color: var(--card-bg-dark, #222);
border-color: var(--card-border-dark, #333);
}
.login-item,
.account-item,
.billing-table th,
.billing-table td {
border-bottom-color: var(--card-border-dark, #333);
}
.toggle-switch {
.toggle-slider {
background-color: #555;
}
}
.btn-outline {
&:hover {
background-color: var(--primary-color, #3498db);
color: #eee;
}
}
}
</style>