800 lines
25 KiB
Vue
800 lines
25 KiB
Vue
<template>
|
|
<v-container fluid class="pa-0">
|
|
<!-- Hero Header Section -->
|
|
<div class="hero-header">
|
|
<v-container class="py-8">
|
|
<div class="d-flex align-center">
|
|
<v-icon color="white" size="40" class="mr-3">mdi-account-circle</v-icon>
|
|
<div>
|
|
<h1 class="text-h4 font-weight-bold text-white mb-1">Profil Saya</h1>
|
|
<p class="text-body-1 text-white opacity-90">Kelola informasi profil dan pengaturan akun Anda</p>
|
|
</div>
|
|
</div>
|
|
</v-container>
|
|
</div>
|
|
|
|
<v-container class="content-container pb-12">
|
|
<v-row>
|
|
<!-- Left Sidebar - Profile Card -->
|
|
<v-col cols="12" lg="4">
|
|
<v-card class="rounded-xl elevation-8 sticky-card profile-card">
|
|
<div class="text-center profile-content">
|
|
<div class="profile-avatar-container">
|
|
<v-avatar size="140" class="profile-avatar elevation-8">
|
|
<v-img
|
|
:src="profileData.picture || 'https://i.pravatar.cc/300?img=68'"
|
|
alt="Profile Picture"
|
|
></v-img>
|
|
</v-avatar>
|
|
<v-btn
|
|
icon
|
|
size="small"
|
|
color="orange-darken-2"
|
|
class="avatar-edit-btn elevation-4"
|
|
@click="openPhotoDialog"
|
|
>
|
|
<v-icon size="18">mdi-camera</v-icon>
|
|
</v-btn>
|
|
</div>
|
|
|
|
<h2 class="text-h5 font-weight-bold mb-2">{{ profileData.name }}</h2>
|
|
<p class="text-body-2 text-grey-darken-1 mb-1">@{{ profileData.username }}</p>
|
|
<p class="text-body-2 text-grey mb-4">{{ profileData.email }}</p>
|
|
|
|
<v-chip
|
|
color="success"
|
|
variant="flat"
|
|
size="small"
|
|
prepend-icon="mdi-check-circle"
|
|
class="mb-4"
|
|
>
|
|
Akun Terverifikasi
|
|
</v-chip>
|
|
|
|
<v-divider class="my-4"></v-divider>
|
|
|
|
<!-- Quick Info -->
|
|
<div class="text-left px-6">
|
|
<div class="info-item mb-3">
|
|
<v-icon size="20" color="blue-darken-2" class="mr-2">mdi-identifier</v-icon>
|
|
<span class="text-body-2 text-grey-darken-1">ID: {{ profileData.id }}</span>
|
|
</div>
|
|
<div class="info-item mb-3">
|
|
<v-icon size="20" color="orange-darken-2" class="mr-2">mdi-calendar-check</v-icon>
|
|
<span class="text-body-2 text-grey-darken-1">Bergabung: {{ profileData.joinDate }}</span>
|
|
</div>
|
|
<div class="info-item">
|
|
<v-icon size="20" color="green-darken-2" class="mr-2">mdi-clock-outline</v-icon>
|
|
<span class="text-body-2 text-grey-darken-1">Login: {{ profileData.lastLogin }}</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<v-card-actions class="pa-4">
|
|
<v-btn
|
|
color="blue-darken-2"
|
|
variant="outlined"
|
|
block
|
|
class="rounded-lg"
|
|
prepend-icon="mdi-cog"
|
|
@click="navigateTo('/Profile/Pengaturan')"
|
|
>
|
|
Pengaturan Akun
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-col>
|
|
|
|
<!-- Right Content - Profile Details -->
|
|
<v-col cols="12" lg="8">
|
|
<!-- Personal Information -->
|
|
<v-card class="rounded-xl elevation-4 mb-4">
|
|
<v-card-title class="d-flex align-center pa-6 pb-4">
|
|
<v-icon color="blue-darken-2" class="mr-2">mdi-account-details</v-icon>
|
|
<span class="font-weight-bold">Informasi Pribadi</span>
|
|
<v-spacer></v-spacer>
|
|
<v-btn
|
|
v-if="!isEditing"
|
|
color="orange-darken-2"
|
|
variant="flat"
|
|
size="small"
|
|
class="rounded-lg"
|
|
prepend-icon="mdi-pencil"
|
|
@click="startEdit"
|
|
>
|
|
Edit
|
|
</v-btn>
|
|
</v-card-title>
|
|
<v-divider></v-divider>
|
|
|
|
<v-card-text class="pa-6">
|
|
<v-form ref="profileForm">
|
|
<v-row>
|
|
<v-col cols="12" md="6">
|
|
<label class="text-caption text-grey-darken-1 font-weight-bold mb-1 d-block">NAMA LENGKAP</label>
|
|
<v-text-field
|
|
v-model="profileData.name"
|
|
placeholder="Masukkan nama lengkap"
|
|
prepend-inner-icon="mdi-account"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
color="blue-darken-2"
|
|
:readonly="!isEditing"
|
|
hide-details="auto"
|
|
class="mb-4"
|
|
></v-text-field>
|
|
</v-col>
|
|
|
|
<v-col cols="12" md="6">
|
|
<label class="text-caption text-grey-darken-1 font-weight-bold mb-1 d-block">USERNAME</label>
|
|
<v-text-field
|
|
v-model="profileData.username"
|
|
placeholder="Masukkan username"
|
|
prepend-inner-icon="mdi-at"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
color="blue-darken-2"
|
|
:readonly="!isEditing"
|
|
hide-details="auto"
|
|
class="mb-4"
|
|
></v-text-field>
|
|
</v-col>
|
|
|
|
<v-col cols="12" md="6">
|
|
<label class="text-caption text-grey-darken-1 font-weight-bold mb-1 d-block">EMAIL</label>
|
|
<v-text-field
|
|
v-model="profileData.email"
|
|
placeholder="Masukkan email"
|
|
prepend-inner-icon="mdi-email"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
color="blue-darken-2"
|
|
:readonly="!isEditing"
|
|
hide-details="auto"
|
|
class="mb-4"
|
|
></v-text-field>
|
|
</v-col>
|
|
|
|
<v-col cols="12" md="6">
|
|
<label class="text-caption text-grey-darken-1 font-weight-bold mb-1 d-block">NOMOR TELEPON</label>
|
|
<v-text-field
|
|
v-model="profileData.phone"
|
|
placeholder="Masukkan nomor telepon"
|
|
prepend-inner-icon="mdi-phone"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
color="blue-darken-2"
|
|
:readonly="!isEditing"
|
|
hide-details="auto"
|
|
class="mb-4"
|
|
></v-text-field>
|
|
</v-col>
|
|
|
|
<v-col cols="12">
|
|
<label class="text-caption text-grey-darken-1 font-weight-bold mb-1 d-block">BIO</label>
|
|
<v-textarea
|
|
v-model="profileData.bio"
|
|
placeholder="Ceritakan tentang diri Anda"
|
|
prepend-inner-icon="mdi-text"
|
|
variant="outlined"
|
|
color="blue-darken-2"
|
|
rows="3"
|
|
:readonly="!isEditing"
|
|
hide-details="auto"
|
|
></v-textarea>
|
|
</v-col>
|
|
</v-row>
|
|
</v-form>
|
|
</v-card-text>
|
|
|
|
<v-divider v-if="isEditing"></v-divider>
|
|
<v-card-actions v-if="isEditing" class="pa-6 pt-4">
|
|
<v-spacer></v-spacer>
|
|
<v-btn
|
|
variant="outlined"
|
|
color="grey-darken-1"
|
|
class="rounded-lg px-6"
|
|
@click="cancelEdit"
|
|
>
|
|
Batal
|
|
</v-btn>
|
|
<v-btn
|
|
color="blue-darken-2"
|
|
variant="flat"
|
|
class="rounded-lg px-8"
|
|
prepend-icon="mdi-check"
|
|
@click="saveProfile"
|
|
:loading="isSaving"
|
|
>
|
|
Simpan Perubahan
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
|
|
<!-- Security Section -->
|
|
<v-card class="rounded-xl elevation-4 mb-4">
|
|
<v-card-title class="d-flex align-center pa-6 pb-4">
|
|
<v-icon color="orange-darken-2" class="mr-2">mdi-shield-check</v-icon>
|
|
<span class="font-weight-bold">Keamanan</span>
|
|
</v-card-title>
|
|
<v-divider></v-divider>
|
|
|
|
<v-card-text class="pa-6">
|
|
<v-list class="transparent">
|
|
<v-list-item
|
|
class="rounded-lg mb-2 px-4"
|
|
prepend-icon="mdi-lock-reset"
|
|
@click="openPasswordDialog"
|
|
>
|
|
<v-list-item-title class="font-weight-medium">Ubah Password</v-list-item-title>
|
|
<v-list-item-subtitle class="text-caption">Perbarui password akun Anda</v-list-item-subtitle>
|
|
<template v-slot:append>
|
|
<v-icon color="grey">mdi-chevron-right</v-icon>
|
|
</template>
|
|
</v-list-item>
|
|
|
|
<v-list-item
|
|
class="rounded-lg mb-2 px-4"
|
|
prepend-icon="mdi-two-factor-authentication"
|
|
>
|
|
<v-list-item-title class="font-weight-medium">Autentikasi Dua Faktor</v-list-item-title>
|
|
<v-list-item-subtitle class="text-caption">Tingkatkan keamanan akun</v-list-item-subtitle>
|
|
<template v-slot:append>
|
|
<v-switch
|
|
v-model="twoFactorEnabled"
|
|
color="blue-darken-2"
|
|
hide-details
|
|
inset
|
|
@change="toggleTwoFactor"
|
|
></v-switch>
|
|
</template>
|
|
</v-list-item>
|
|
|
|
<v-list-item
|
|
class="rounded-lg px-4"
|
|
prepend-icon="mdi-devices"
|
|
@click="openDevicesDialog"
|
|
>
|
|
<v-list-item-title class="font-weight-medium">Perangkat Aktif</v-list-item-title>
|
|
<v-list-item-subtitle class="text-caption">Kelola perangkat yang terhubung</v-list-item-subtitle>
|
|
<template v-slot:append>
|
|
<v-chip size="small" color="success" variant="flat">{{ activeSessions.length }} Perangkat</v-chip>
|
|
</template>
|
|
</v-list-item>
|
|
</v-list>
|
|
</v-card-text>
|
|
</v-card>
|
|
|
|
<!-- Preferences Section -->
|
|
<v-card class="rounded-xl elevation-4">
|
|
<v-card-title class="d-flex align-center pa-6 pb-4">
|
|
<v-icon color="blue-darken-2" class="mr-2">mdi-tune</v-icon>
|
|
<span class="font-weight-bold">Preferensi</span>
|
|
</v-card-title>
|
|
<v-divider></v-divider>
|
|
|
|
<v-card-text class="pa-6">
|
|
<v-list class="transparent">
|
|
<v-list-item class="rounded-lg mb-2 px-4" prepend-icon="mdi-bell">
|
|
<v-list-item-title class="font-weight-medium">Notifikasi Email</v-list-item-title>
|
|
<v-list-item-subtitle class="text-caption">Terima update via email</v-list-item-subtitle>
|
|
<template v-slot:append>
|
|
<v-switch
|
|
v-model="emailNotifications"
|
|
color="orange-darken-2"
|
|
hide-details
|
|
inset
|
|
></v-switch>
|
|
</template>
|
|
</v-list-item>
|
|
|
|
<v-list-item class="rounded-lg mb-2 px-4" prepend-icon="mdi-theme-light-dark">
|
|
<v-list-item-title class="font-weight-medium">Tema Gelap</v-list-item-title>
|
|
<v-list-item-subtitle class="text-caption">Aktifkan mode gelap</v-list-item-subtitle>
|
|
<template v-slot:append>
|
|
<v-switch
|
|
v-model="darkMode"
|
|
color="blue-darken-2"
|
|
hide-details
|
|
inset
|
|
></v-switch>
|
|
</template>
|
|
</v-list-item>
|
|
|
|
<v-list-item class="rounded-lg px-4" prepend-icon="mdi-web">
|
|
<v-list-item-title class="font-weight-medium">Bahasa</v-list-item-title>
|
|
<v-list-item-subtitle class="text-caption">Indonesia</v-list-item-subtitle>
|
|
<template v-slot:append>
|
|
<v-icon color="grey">mdi-chevron-right</v-icon>
|
|
</template>
|
|
</v-list-item>
|
|
</v-list>
|
|
</v-card-text>
|
|
</v-card>
|
|
</v-col>
|
|
</v-row>
|
|
</v-container>
|
|
|
|
Change Password Dialog
|
|
<v-dialog v-model="passwordDialog" max-width="500" persistent>
|
|
<v-card class="rounded-xl">
|
|
<v-card-title class="pa-6 pb-4">
|
|
<div class="d-flex align-center">
|
|
<v-icon color="orange-darken-2" class="mr-2">mdi-lock-reset</v-icon>
|
|
<span class="font-weight-bold">Ubah Password</span>
|
|
</div>
|
|
</v-card-title>
|
|
<v-divider></v-divider>
|
|
|
|
<v-card-text class="pa-6">
|
|
<v-form ref="passwordForm">
|
|
<label class="text-caption text-grey-darken-1 font-weight-bold mb-1 d-block">PASSWORD SAAT INI</label>
|
|
<v-text-field
|
|
v-model="passwordData.current"
|
|
type="password"
|
|
prepend-inner-icon="mdi-lock"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
color="blue-darken-2"
|
|
hide-details="auto"
|
|
class="mb-4"
|
|
></v-text-field>
|
|
|
|
<label class="text-caption text-grey-darken-1 font-weight-bold mb-1 d-block">PASSWORD BARU</label>
|
|
<v-text-field
|
|
v-model="passwordData.new"
|
|
type="password"
|
|
prepend-inner-icon="mdi-lock-plus"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
color="blue-darken-2"
|
|
hide-details="auto"
|
|
class="mb-4"
|
|
></v-text-field>
|
|
|
|
<label class="text-caption text-grey-darken-1 font-weight-bold mb-1 d-block">KONFIRMASI PASSWORD</label>
|
|
<v-text-field
|
|
v-model="passwordData.confirm"
|
|
type="password"
|
|
prepend-inner-icon="mdi-lock-check"
|
|
variant="outlined"
|
|
density="comfortable"
|
|
color="blue-darken-2"
|
|
hide-details="auto"
|
|
></v-text-field>
|
|
</v-form>
|
|
</v-card-text>
|
|
|
|
<v-divider></v-divider>
|
|
<v-card-actions class="pa-6 pt-4">
|
|
<v-spacer></v-spacer>
|
|
<v-btn
|
|
variant="outlined"
|
|
color="grey-darken-1"
|
|
class="rounded-lg"
|
|
@click="passwordDialog = false"
|
|
>
|
|
Batal
|
|
</v-btn>
|
|
<v-btn
|
|
color="orange-darken-2"
|
|
variant="flat"
|
|
class="rounded-lg px-6"
|
|
@click="changePassword"
|
|
:loading="isChangingPassword"
|
|
>
|
|
Ubah Password
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
|
|
<!-- Active Devices Dialog -->
|
|
<v-dialog v-model="devicesDialog" max-width="700" scrollable>
|
|
<v-card class="rounded-xl">
|
|
<v-card-title class="pa-6 pb-4">
|
|
<div class="d-flex align-center">
|
|
<v-icon color="blue-darken-2" class="mr-2">mdi-devices</v-icon>
|
|
<span class="font-weight-bold">Perangkat Aktif</span>
|
|
</div>
|
|
</v-card-title>
|
|
<v-divider></v-divider>
|
|
|
|
<v-card-text class="pa-0" style="max-height: 500px;">
|
|
<v-list class="py-0">
|
|
<v-list-item
|
|
v-for="(session, index) in activeSessions"
|
|
:key="index"
|
|
class="py-4 px-6"
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-avatar :color="session.current ? 'success' : 'blue-grey-lighten-4'" size="48">
|
|
<v-icon :color="session.current ? 'white' : 'blue-grey-darken-2'">
|
|
{{ session.icon }}
|
|
</v-icon>
|
|
</v-avatar>
|
|
</template>
|
|
|
|
<v-list-item-title class="font-weight-bold mb-1">
|
|
{{ session.device }}
|
|
<v-chip v-if="session.current" size="x-small" color="success" class="ml-2">
|
|
Sesi Ini
|
|
</v-chip>
|
|
</v-list-item-title>
|
|
<v-list-item-subtitle class="text-caption">
|
|
<div>{{ session.location }}</div>
|
|
<div class="text-grey-darken-1 mt-1">
|
|
<v-icon size="12">mdi-clock-outline</v-icon>
|
|
{{ session.lastActive }}
|
|
</div>
|
|
</v-list-item-subtitle>
|
|
|
|
<template v-slot:append v-if="!session.current">
|
|
<v-btn
|
|
icon="mdi-close-circle"
|
|
size="small"
|
|
variant="text"
|
|
color="error"
|
|
@click="removeSession(index)"
|
|
></v-btn>
|
|
</template>
|
|
</v-list-item>
|
|
</v-list>
|
|
</v-card-text>
|
|
|
|
<v-divider></v-divider>
|
|
<v-card-actions class="pa-6 pt-4">
|
|
<v-btn
|
|
color="error"
|
|
variant="outlined"
|
|
class="rounded-lg"
|
|
prepend-icon="mdi-logout-variant"
|
|
@click="logoutAllDevices"
|
|
>
|
|
Keluar dari Semua Perangkat
|
|
</v-btn>
|
|
<v-spacer></v-spacer>
|
|
<v-btn
|
|
variant="text"
|
|
class="rounded-lg"
|
|
@click="devicesDialog = false"
|
|
>
|
|
Tutup
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
|
|
<!-- Photo Upload Dialog -->
|
|
<v-dialog v-model="photoDialog" max-width="400">
|
|
<v-card class="rounded-xl">
|
|
<v-card-title class="pa-6 pb-4">
|
|
<div class="d-flex align-center">
|
|
<v-icon color="blue-darken-2" class="mr-2">mdi-camera</v-icon>
|
|
<span class="font-weight-bold">Ubah Foto Profil</span>
|
|
</div>
|
|
</v-card-title>
|
|
<v-divider></v-divider>
|
|
|
|
<v-card-text class="pa-6 text-center">
|
|
<v-avatar size="150" class="mb-4">
|
|
<v-img :src="profileData.picture"></v-img>
|
|
</v-avatar>
|
|
<v-file-input
|
|
label="Pilih foto baru"
|
|
variant="outlined"
|
|
prepend-icon=""
|
|
prepend-inner-icon="mdi-image"
|
|
accept="image/*"
|
|
hide-details
|
|
></v-file-input>
|
|
</v-card-text>
|
|
|
|
<v-divider></v-divider>
|
|
<v-card-actions class="pa-6 pt-4">
|
|
<v-btn
|
|
color="error"
|
|
variant="text"
|
|
class="rounded-lg"
|
|
>
|
|
Hapus Foto
|
|
</v-btn>
|
|
<v-spacer></v-spacer>
|
|
<v-btn
|
|
variant="outlined"
|
|
color="grey-darken-1"
|
|
class="rounded-lg"
|
|
@click="photoDialog = false"
|
|
>
|
|
Batal
|
|
</v-btn>
|
|
<v-btn
|
|
color="blue-darken-2"
|
|
variant="flat"
|
|
class="rounded-lg px-6"
|
|
>
|
|
Simpan
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
|
|
<!-- Success Snackbar -->
|
|
<v-snackbar
|
|
v-model="snackbar"
|
|
:color="snackbarColor"
|
|
location="top"
|
|
timeout="3000"
|
|
class="snackbar-custom"
|
|
>
|
|
<div class="d-flex align-center">
|
|
<v-icon class="mr-2">{{ snackbarIcon }}</v-icon>
|
|
<span>{{ snackbarMessage }}</span>
|
|
</div>
|
|
<template v-slot:actions>
|
|
<v-btn
|
|
variant="text"
|
|
size="small"
|
|
icon="mdi-close"
|
|
@click="snackbar = false"
|
|
></v-btn>
|
|
</template>
|
|
</v-snackbar>
|
|
</v-container>
|
|
</template>
|
|
|
|
<script setup>
|
|
import { ref, reactive, computed } from 'vue';
|
|
import { navigateTo } from '#app';
|
|
|
|
definePageMeta({
|
|
middleware: 'auth'
|
|
});
|
|
|
|
const isEditing = ref(false);
|
|
const isSaving = ref(false);
|
|
const isChangingPassword = ref(false);
|
|
const snackbar = ref(false);
|
|
const snackbarMessage = ref('');
|
|
const snackbarColor = ref('success');
|
|
|
|
const passwordDialog = ref(false);
|
|
const devicesDialog = ref(false);
|
|
const photoDialog = ref(false);
|
|
|
|
const twoFactorEnabled = ref(false);
|
|
const emailNotifications = ref(true);
|
|
const darkMode = ref(false);
|
|
|
|
const snackbarIcon = computed(() => {
|
|
return snackbarColor.value === 'success' ? 'mdi-check-circle' : 'mdi-alert-circle';
|
|
});
|
|
|
|
const profileData = reactive({
|
|
id: 'USR-12345678',
|
|
name: 'John Doe',
|
|
username: 'johndoe',
|
|
email: 'john.doe@example.com',
|
|
phone: '+62 812 3456 7890',
|
|
bio: 'Passionate developer and tech enthusiast. Love building beautiful and functional web applications.',
|
|
picture: 'https://i.pravatar.cc/300?img=68',
|
|
joinDate: '15 Januari 2024',
|
|
lastLogin: '16 Oktober 2025, 10:30 AM'
|
|
});
|
|
|
|
const passwordData = reactive({
|
|
current: '',
|
|
new: '',
|
|
confirm: ''
|
|
});
|
|
|
|
const activeSessions = ref([
|
|
{
|
|
device: 'Chrome on Windows 11',
|
|
location: 'Sidoarjo, Indonesia',
|
|
lastActive: 'Sekarang',
|
|
icon: 'mdi-laptop',
|
|
current: true
|
|
},
|
|
{
|
|
device: 'Mobile App on Android',
|
|
location: 'Surabaya, Indonesia',
|
|
lastActive: '2 jam yang lalu',
|
|
icon: 'mdi-cellphone',
|
|
current: false
|
|
},
|
|
{
|
|
device: 'Safari on macOS',
|
|
location: 'Jakarta, Indonesia',
|
|
lastActive: '1 hari yang lalu',
|
|
icon: 'mdi-laptop',
|
|
current: false
|
|
}
|
|
]);
|
|
|
|
const originalData = ref({});
|
|
|
|
const startEdit = () => {
|
|
originalData.value = { ...profileData };
|
|
isEditing.value = true;
|
|
};
|
|
|
|
const cancelEdit = () => {
|
|
Object.assign(profileData, originalData.value);
|
|
isEditing.value = false;
|
|
};
|
|
|
|
const saveProfile = async () => {
|
|
isSaving.value = true;
|
|
|
|
try {
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
// TODO: Replace with actual API call
|
|
// await $fetch('/api/profile/update', {
|
|
// method: 'PUT',
|
|
// body: profileData
|
|
// });
|
|
|
|
originalData.value = { ...profileData };
|
|
isEditing.value = false;
|
|
snackbarMessage.value = 'Profil berhasil diperbarui!';
|
|
snackbarColor.value = 'success';
|
|
snackbar.value = true;
|
|
} catch (error) {
|
|
snackbarMessage.value = 'Gagal memperbarui profil!';
|
|
snackbarColor.value = 'error';
|
|
snackbar.value = true;
|
|
} finally {
|
|
isSaving.value = false;
|
|
}
|
|
};
|
|
|
|
const openPhotoDialog = () => {
|
|
photoDialog.value = true;
|
|
};
|
|
|
|
const openPasswordDialog = () => {
|
|
passwordDialog.value = true;
|
|
passwordData.current = '';
|
|
passwordData.new = '';
|
|
passwordData.confirm = '';
|
|
};
|
|
|
|
const changePassword = async () => {
|
|
if (passwordData.new !== passwordData.confirm) {
|
|
snackbarMessage.value = 'Password baru tidak cocok!';
|
|
snackbarColor.value = 'error';
|
|
snackbar.value = true;
|
|
return;
|
|
}
|
|
|
|
isChangingPassword.value = true;
|
|
try {
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
// TODO: Replace with actual API call
|
|
|
|
passwordDialog.value = false;
|
|
snackbarMessage.value = 'Password berhasil diubah!';
|
|
snackbarColor.value = 'success';
|
|
snackbar.value = true;
|
|
} catch (error) {
|
|
snackbarMessage.value = 'Gagal mengubah password!';
|
|
snackbarColor.value = 'error';
|
|
snackbar.value = true;
|
|
} finally {
|
|
isChangingPassword.value = false;
|
|
}
|
|
};
|
|
|
|
const openDevicesDialog = () => {
|
|
devicesDialog.value = true;
|
|
};
|
|
|
|
const removeSession = (index) => {
|
|
activeSessions.value.splice(index, 1);
|
|
snackbarMessage.value = 'Perangkat berhasil dihapus dari sesi aktif';
|
|
snackbarColor.value = 'success';
|
|
snackbar.value = true;
|
|
};
|
|
|
|
const logoutAllDevices = () => {
|
|
// Keep only current session
|
|
activeSessions.value = activeSessions.value.filter(s => s.current);
|
|
devicesDialog.value = false;
|
|
snackbarMessage.value = 'Berhasil keluar dari semua perangkat lain';
|
|
snackbarColor.value = 'success';
|
|
snackbar.value = true;
|
|
};
|
|
|
|
const toggleTwoFactor = () => {
|
|
const status = twoFactorEnabled.value ? 'diaktifkan' : 'dinonaktifkan';
|
|
snackbarMessage.value = `Autentikasi dua faktor ${status}`;
|
|
snackbarColor.value = 'info';
|
|
snackbar.value = true;
|
|
};
|
|
|
|
// Initialize original data
|
|
originalData.value = { ...profileData };
|
|
</script>
|
|
|
|
<style scoped>
|
|
.hero-header {
|
|
background: linear-gradient(135deg, #1976d2 0%, #1565c0 50%, #f57c00 100%);
|
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
|
|
position: relative;
|
|
z-index: 1;
|
|
}
|
|
|
|
.content-container {
|
|
margin-top: 40px;
|
|
}
|
|
|
|
.sticky-card {
|
|
position: sticky;
|
|
top: 80px;
|
|
}
|
|
|
|
.profile-card {
|
|
overflow: visible;
|
|
}
|
|
|
|
.profile-content {
|
|
padding-top: 0;
|
|
padding-bottom: 20px;
|
|
}
|
|
|
|
.profile-avatar-container {
|
|
position: relative;
|
|
display: inline-block;
|
|
margin-top: -70px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.profile-avatar {
|
|
border: 6px solid white;
|
|
background: white;
|
|
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.2);
|
|
}
|
|
|
|
.avatar-edit-btn {
|
|
position: absolute;
|
|
bottom: 8px;
|
|
right: 8px;
|
|
width: 32px;
|
|
height: 32px;
|
|
}
|
|
|
|
.stat-item {
|
|
text-align: center;
|
|
}
|
|
|
|
.info-item {
|
|
display: flex;
|
|
align-items: center;
|
|
}
|
|
|
|
label {
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.v-list-item {
|
|
transition: background-color 0.2s;
|
|
}
|
|
|
|
.v-list-item:hover {
|
|
background-color: rgba(0, 0, 0, 0.03);
|
|
}
|
|
|
|
.snackbar-custom {
|
|
font-weight: 500;
|
|
}
|
|
|
|
@media (max-width: 1280px) {
|
|
.sticky-card {
|
|
position: relative;
|
|
top: 0;
|
|
}
|
|
}
|
|
</style> |