monacousa-portal/pages/member/profile/index.vue

640 lines
20 KiB
Vue

<template>
<div>
<!-- Header -->
<div class="mb-6">
<h1 class="text-h4 font-weight-bold mb-2">My Profile</h1>
<p class="text-body-1 text-medium-emphasis">Manage your personal information and preferences</p>
</div>
<!-- Profile Completion Alert -->
<v-alert
v-if="profileCompletion < 100"
type="info"
variant="tonal"
class="mb-6"
closable
>
<v-alert-title>Complete Your Profile</v-alert-title>
Your profile is {{ profileCompletion }}% complete. Add more information to help other members connect with you.
<v-progress-linear
:model-value="profileCompletion"
color="info"
class="mt-2"
height="6"
rounded
/>
</v-alert>
<v-row>
<!-- Left Column - Profile Card -->
<v-col cols="12" lg="4">
<v-card elevation="2" class="mb-6">
<v-card-text class="text-center pa-6">
<!-- Avatar -->
<div class="mb-4">
<ProfileAvatar
:member-id="profile.memberId"
:first-name="profile.firstName"
:last-name="profile.lastName"
size="x-large"
:show-badge="false"
/>
<v-btn
color="error"
variant="text"
size="small"
class="mt-2"
@click="changeAvatar"
>
<v-icon start>mdi-camera</v-icon>
Change Photo
</v-btn>
</div>
<!-- Basic Info -->
<h2 class="text-h5 font-weight-bold mb-1">{{ profile.firstName }} {{ profile.lastName }}</h2>
<p class="text-body-2 text-medium-emphasis mb-3">{{ profile.title }}</p>
<!-- Member Badge -->
<v-chip
color="error"
variant="tonal"
class="mb-4"
>
<v-icon start>mdi-shield-star</v-icon>
{{ profile.memberType }} Member
</v-chip>
<!-- Stats -->
<v-row class="mt-4">
<v-col cols="4">
<div class="text-h6 font-weight-bold">{{ profile.eventsAttended }}</div>
<div class="text-caption text-medium-emphasis">Events</div>
</v-col>
<v-col cols="4">
<div class="text-h6 font-weight-bold">{{ profile.connections }}</div>
<div class="text-caption text-medium-emphasis">Connections</div>
</v-col>
<v-col cols="4">
<div class="text-h6 font-weight-bold">{{ profile.yearJoined }}</div>
<div class="text-caption text-medium-emphasis">Joined</div>
</v-col>
</v-row>
</v-card-text>
</v-card>
<!-- Quick Actions -->
<v-card elevation="1">
<v-card-title class="text-body-1">Quick Actions</v-card-title>
<v-list density="compact">
<v-list-item @click="downloadMemberCard">
<template v-slot:prepend>
<v-icon color="error">mdi-card-account-details</v-icon>
</template>
<v-list-item-title>Download Member Card</v-list-item-title>
</v-list-item>
<v-list-item @click="exportData">
<template v-slot:prepend>
<v-icon color="error">mdi-download</v-icon>
</template>
<v-list-item-title>Export My Data</v-list-item-title>
</v-list-item>
<v-list-item @click="privacySettings">
<template v-slot:prepend>
<v-icon color="error">mdi-shield-lock</v-icon>
</template>
<v-list-item-title>Privacy Settings</v-list-item-title>
</v-list-item>
</v-list>
</v-card>
</v-col>
<!-- Right Column - Profile Details -->
<v-col cols="12" lg="8">
<!-- Tab Navigation -->
<v-tabs
v-model="activeTab"
color="error"
class="mb-6"
>
<v-tab value="personal">
<v-icon start>mdi-account</v-icon>
Personal Info
</v-tab>
<v-tab value="contact">
<v-icon start>mdi-phone</v-icon>
Contact
</v-tab>
<v-tab value="professional">
<v-icon start>mdi-briefcase</v-icon>
Professional
</v-tab>
<v-tab value="preferences">
<v-icon start>mdi-cog</v-icon>
Preferences
</v-tab>
</v-tabs>
<!-- Tab Content -->
<v-window v-model="activeTab">
<!-- Personal Info Tab -->
<v-window-item value="personal">
<v-card elevation="1">
<v-card-title>
Personal Information
<v-spacer />
<v-btn
v-if="!editingPersonal"
variant="text"
color="error"
@click="editingPersonal = true"
>
<v-icon start>mdi-pencil</v-icon>
Edit
</v-btn>
</v-card-title>
<v-card-text>
<v-form v-model="personalFormValid">
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="profile.firstName"
label="First Name"
variant="outlined"
:readonly="!editingPersonal"
:rules="editingPersonal ? [v => !!v || 'Required'] : []"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="profile.lastName"
label="Last Name"
variant="outlined"
:readonly="!editingPersonal"
:rules="editingPersonal ? [v => !!v || 'Required'] : []"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="profile.dateOfBirth"
label="Date of Birth"
type="date"
variant="outlined"
:readonly="!editingPersonal"
/>
</v-col>
<v-col cols="12" md="6">
<v-select
v-model="profile.nationality"
label="Nationality"
:items="nationalities"
variant="outlined"
:readonly="!editingPersonal"
/>
</v-col>
<v-col cols="12">
<v-textarea
v-model="profile.bio"
label="Bio"
variant="outlined"
rows="3"
:readonly="!editingPersonal"
placeholder="Tell us about yourself..."
/>
</v-col>
</v-row>
</v-form>
</v-card-text>
<v-card-actions v-if="editingPersonal">
<v-spacer />
<v-btn variant="text" @click="cancelEditPersonal">Cancel</v-btn>
<v-btn
color="error"
variant="flat"
:disabled="!personalFormValid"
@click="savePersonal"
>
Save Changes
</v-btn>
</v-card-actions>
</v-card>
</v-window-item>
<!-- Contact Tab -->
<v-window-item value="contact">
<v-card elevation="1">
<v-card-title>
Contact Information
<v-spacer />
<v-btn
v-if="!editingContact"
variant="text"
color="error"
@click="editingContact = true"
>
<v-icon start>mdi-pencil</v-icon>
Edit
</v-btn>
</v-card-title>
<v-card-text>
<v-form v-model="contactFormValid">
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="profile.email"
label="Email"
type="email"
variant="outlined"
:readonly="!editingContact"
:rules="editingContact ? [v => !!v || 'Required', v => /.+@.+/.test(v) || 'Invalid email'] : []"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="profile.phone"
label="Phone"
variant="outlined"
:readonly="!editingContact"
/>
</v-col>
<v-col cols="12">
<v-text-field
v-model="profile.address"
label="Address"
variant="outlined"
:readonly="!editingContact"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="profile.city"
label="City"
variant="outlined"
:readonly="!editingContact"
/>
</v-col>
<v-col cols="12" md="3">
<v-text-field
v-model="profile.state"
label="State"
variant="outlined"
:readonly="!editingContact"
/>
</v-col>
<v-col cols="12" md="3">
<v-text-field
v-model="profile.zipCode"
label="ZIP Code"
variant="outlined"
:readonly="!editingContact"
/>
</v-col>
</v-row>
</v-form>
</v-card-text>
<v-card-actions v-if="editingContact">
<v-spacer />
<v-btn variant="text" @click="cancelEditContact">Cancel</v-btn>
<v-btn
color="error"
variant="flat"
:disabled="!contactFormValid"
@click="saveContact"
>
Save Changes
</v-btn>
</v-card-actions>
</v-card>
</v-window-item>
<!-- Professional Tab -->
<v-window-item value="professional">
<v-card elevation="1">
<v-card-title>
Professional Information
<v-spacer />
<v-btn
v-if="!editingProfessional"
variant="text"
color="error"
@click="editingProfessional = true"
>
<v-icon start>mdi-pencil</v-icon>
Edit
</v-btn>
</v-card-title>
<v-card-text>
<v-form v-model="professionalFormValid">
<v-row>
<v-col cols="12" md="6">
<v-text-field
v-model="profile.company"
label="Company"
variant="outlined"
:readonly="!editingProfessional"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="profile.title"
label="Job Title"
variant="outlined"
:readonly="!editingProfessional"
/>
</v-col>
<v-col cols="12" md="6">
<v-select
v-model="profile.industry"
label="Industry"
:items="industries"
variant="outlined"
:readonly="!editingProfessional"
/>
</v-col>
<v-col cols="12" md="6">
<v-text-field
v-model="profile.linkedin"
label="LinkedIn Profile"
variant="outlined"
:readonly="!editingProfessional"
placeholder="https://linkedin.com/in/..."
/>
</v-col>
<v-col cols="12">
<v-textarea
v-model="profile.expertise"
label="Areas of Expertise"
variant="outlined"
rows="2"
:readonly="!editingProfessional"
placeholder="e.g., Finance, Marketing, Technology..."
/>
</v-col>
</v-row>
</v-form>
</v-card-text>
<v-card-actions v-if="editingProfessional">
<v-spacer />
<v-btn variant="text" @click="cancelEditProfessional">Cancel</v-btn>
<v-btn
color="error"
variant="flat"
:disabled="!professionalFormValid"
@click="saveProfessional"
>
Save Changes
</v-btn>
</v-card-actions>
</v-card>
</v-window-item>
<!-- Preferences Tab -->
<v-window-item value="preferences">
<v-card elevation="1" class="mb-4">
<v-card-title>Communication Preferences</v-card-title>
<v-card-text>
<v-switch
v-model="preferences.emailNotifications"
label="Email Notifications"
color="error"
hide-details
class="mb-3"
/>
<v-switch
v-model="preferences.eventReminders"
label="Event Reminders"
color="error"
hide-details
class="mb-3"
/>
<v-switch
v-model="preferences.newsletter"
label="Monthly Newsletter"
color="error"
hide-details
class="mb-3"
/>
<v-switch
v-model="preferences.memberUpdates"
label="Member Updates"
color="error"
hide-details
/>
</v-card-text>
</v-card>
<v-card elevation="1">
<v-card-title>Privacy Settings</v-card-title>
<v-card-text>
<v-switch
v-model="preferences.profileVisible"
label="Profile visible to other members"
color="error"
hide-details
class="mb-3"
/>
<v-switch
v-model="preferences.showEmail"
label="Show email in member directory"
color="error"
hide-details
class="mb-3"
/>
<v-switch
v-model="preferences.showPhone"
label="Show phone in member directory"
color="error"
hide-details
/>
</v-card-text>
<v-card-actions>
<v-spacer />
<v-btn
color="error"
variant="flat"
@click="savePreferences"
>
Save Preferences
</v-btn>
</v-card-actions>
</v-card>
</v-window-item>
</v-window>
</v-col>
</v-row>
</div>
</template>
<script setup lang="ts">
import type { Member } from '~/utils/types';
definePageMeta({
layout: 'member',
middleware: 'member'
});
const { user } = useAuth();
// State
const activeTab = ref('personal');
const editingPersonal = ref(false);
const editingContact = ref(false);
const editingProfessional = ref(false);
const personalFormValid = ref(true);
const contactFormValid = ref(true);
const professionalFormValid = ref(true);
// Profile data
const profile = ref({
memberId: 'MUSA-0001',
firstName: 'John',
lastName: 'Doe',
email: 'john.doe@example.com',
phone: '+1 234 567 8900',
dateOfBirth: '1985-06-15',
nationality: 'United States',
bio: 'Passionate about business and innovation. Active member of the Monaco business community.',
address: '123 Main Street',
city: 'Monaco',
state: 'MC',
zipCode: '98000',
company: 'Tech Innovations Inc.',
title: 'CEO & Founder',
industry: 'Technology',
linkedin: 'https://linkedin.com/in/johndoe',
expertise: 'Technology, Innovation, Business Strategy',
memberType: 'Premium',
eventsAttended: 24,
connections: 156,
yearJoined: '2021'
});
// Preferences
const preferences = ref({
emailNotifications: true,
eventReminders: true,
newsletter: true,
memberUpdates: false,
profileVisible: true,
showEmail: false,
showPhone: false
});
// Options
const nationalities = ref([
'United States',
'Monaco',
'France',
'Italy',
'United Kingdom',
'Germany',
'Spain',
'Other'
]);
const industries = ref([
'Technology',
'Finance',
'Healthcare',
'Real Estate',
'Hospitality',
'Manufacturing',
'Retail',
'Education',
'Other'
]);
// Computed
const profileCompletion = computed(() => {
let completed = 0;
const fields = [
profile.value.firstName,
profile.value.lastName,
profile.value.email,
profile.value.phone,
profile.value.dateOfBirth,
profile.value.nationality,
profile.value.bio,
profile.value.address,
profile.value.company,
profile.value.title
];
fields.forEach(field => {
if (field) completed += 10;
});
return completed;
});
// Methods
const changeAvatar = () => {
console.log('Change avatar');
};
const downloadMemberCard = () => {
console.log('Download member card');
};
const exportData = () => {
console.log('Export user data');
};
const privacySettings = () => {
activeTab.value = 'preferences';
};
const cancelEditPersonal = () => {
editingPersonal.value = false;
// Reset form if needed
};
const savePersonal = () => {
console.log('Saving personal info');
editingPersonal.value = false;
};
const cancelEditContact = () => {
editingContact.value = false;
};
const saveContact = () => {
console.log('Saving contact info');
editingContact.value = false;
};
const cancelEditProfessional = () => {
editingProfessional.value = false;
};
const saveProfessional = () => {
console.log('Saving professional info');
editingProfessional.value = false;
};
const savePreferences = () => {
console.log('Saving preferences', preferences.value);
};
// Load real member data on mount
onMounted(async () => {
try {
const { data: sessionData } = await $fetch<{ success: boolean; member: Member | null }>('/api/auth/session');
if (sessionData?.member) {
// Map real data to profile
profile.value.firstName = sessionData.member.first_name || profile.value.firstName;
profile.value.lastName = sessionData.member.last_name || profile.value.lastName;
profile.value.email = sessionData.member.email || profile.value.email;
profile.value.phone = sessionData.member.phone || profile.value.phone;
profile.value.nationality = sessionData.member.nationality || profile.value.nationality;
profile.value.memberId = sessionData.member.member_id || profile.value.memberId;
}
} catch (error) {
console.error('Error loading member data:', error);
}
});
</script>
<style scoped>
/* Custom styles if needed */
</style>