552 lines
17 KiB
Vue
552 lines
17 KiB
Vue
<template>
|
|
<div>
|
|
<!-- Header -->
|
|
<div class="mb-6">
|
|
<h1 class="text-h4 font-weight-bold mb-2">Events</h1>
|
|
<p class="text-body-1 text-medium-emphasis">Discover and register for upcoming MonacoUSA events</p>
|
|
</div>
|
|
|
|
<!-- Filters -->
|
|
<v-card class="mb-6" elevation="1">
|
|
<v-card-text>
|
|
<v-row align="center">
|
|
<v-col cols="12" md="4">
|
|
<v-text-field
|
|
v-model="searchQuery"
|
|
prepend-inner-icon="mdi-magnify"
|
|
label="Search events"
|
|
variant="outlined"
|
|
density="compact"
|
|
clearable
|
|
hide-details
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12" md="3">
|
|
<v-select
|
|
v-model="selectedCategory"
|
|
:items="categories"
|
|
label="Category"
|
|
variant="outlined"
|
|
density="compact"
|
|
clearable
|
|
hide-details
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12" md="3">
|
|
<v-select
|
|
v-model="selectedMonth"
|
|
:items="months"
|
|
label="Month"
|
|
variant="outlined"
|
|
density="compact"
|
|
clearable
|
|
hide-details
|
|
/>
|
|
</v-col>
|
|
<v-col cols="12" md="2">
|
|
<v-btn
|
|
color="error"
|
|
variant="flat"
|
|
block
|
|
@click="resetFilters"
|
|
>
|
|
Reset Filters
|
|
</v-btn>
|
|
</v-col>
|
|
</v-row>
|
|
</v-card-text>
|
|
</v-card>
|
|
|
|
<!-- Event Tabs -->
|
|
<v-tabs
|
|
v-model="tab"
|
|
color="error"
|
|
class="mb-6"
|
|
>
|
|
<v-tab value="upcoming">
|
|
<v-icon start>mdi-calendar-clock</v-icon>
|
|
Upcoming Events
|
|
</v-tab>
|
|
<v-tab value="registered">
|
|
<v-icon start>mdi-calendar-check</v-icon>
|
|
My Registrations
|
|
</v-tab>
|
|
<v-tab value="past">
|
|
<v-icon start>mdi-history</v-icon>
|
|
Past Events
|
|
</v-tab>
|
|
</v-tabs>
|
|
|
|
<!-- Tab Content -->
|
|
<v-window v-model="tab">
|
|
<!-- Upcoming Events Tab -->
|
|
<v-window-item value="upcoming">
|
|
<v-row>
|
|
<v-col
|
|
v-for="event in upcomingEvents"
|
|
:key="event.id"
|
|
cols="12"
|
|
md="6"
|
|
lg="4"
|
|
>
|
|
<v-card elevation="2" hover class="h-100 d-flex flex-column">
|
|
<!-- Event Image -->
|
|
<v-img
|
|
:src="event.image"
|
|
height="200"
|
|
cover
|
|
gradient="to bottom, rgba(0,0,0,.1), rgba(0,0,0,.5)"
|
|
>
|
|
<v-card-title class="text-white">
|
|
{{ event.title }}
|
|
</v-card-title>
|
|
</v-img>
|
|
|
|
<v-card-text class="flex-grow-1">
|
|
<!-- Event Details -->
|
|
<div class="mb-3">
|
|
<v-chip
|
|
:color="getCategoryColor(event.category)"
|
|
size="small"
|
|
variant="tonal"
|
|
class="mb-2"
|
|
>
|
|
{{ event.category }}
|
|
</v-chip>
|
|
</div>
|
|
|
|
<p class="text-body-2 mb-3">{{ event.description }}</p>
|
|
|
|
<div class="text-caption text-medium-emphasis">
|
|
<div class="d-flex align-center mb-1">
|
|
<v-icon size="x-small" class="mr-2">mdi-calendar</v-icon>
|
|
{{ formatDate(event.date) }}
|
|
</div>
|
|
<div class="d-flex align-center mb-1">
|
|
<v-icon size="x-small" class="mr-2">mdi-clock-outline</v-icon>
|
|
{{ event.time }}
|
|
</div>
|
|
<div class="d-flex align-center mb-1">
|
|
<v-icon size="x-small" class="mr-2">mdi-map-marker</v-icon>
|
|
{{ event.location }}
|
|
</div>
|
|
<div class="d-flex align-center">
|
|
<v-icon size="x-small" class="mr-2">mdi-account-group</v-icon>
|
|
{{ event.attendees }} / {{ event.capacity }} attendees
|
|
</div>
|
|
</div>
|
|
</v-card-text>
|
|
|
|
<v-card-actions>
|
|
<v-spacer />
|
|
<v-btn
|
|
variant="text"
|
|
color="error"
|
|
@click="viewEventDetails(event)"
|
|
>
|
|
Learn More
|
|
</v-btn>
|
|
<v-btn
|
|
variant="flat"
|
|
color="error"
|
|
:disabled="event.attendees >= event.capacity"
|
|
@click="registerForEvent(event)"
|
|
>
|
|
{{ event.attendees >= event.capacity ? 'Full' : 'Register' }}
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-col>
|
|
</v-row>
|
|
|
|
<!-- Empty State -->
|
|
<v-card v-if="upcomingEvents.length === 0" class="text-center pa-8" elevation="0">
|
|
<v-icon size="64" color="grey-lighten-1">mdi-calendar-blank</v-icon>
|
|
<h3 class="text-h6 mt-4">No upcoming events</h3>
|
|
<p class="text-body-2 text-medium-emphasis">Check back later for new events</p>
|
|
</v-card>
|
|
</v-window-item>
|
|
|
|
<!-- Registered Events Tab -->
|
|
<v-window-item value="registered">
|
|
<v-row>
|
|
<v-col cols="12">
|
|
<v-card elevation="1">
|
|
<v-list lines="three">
|
|
<v-list-item
|
|
v-for="registration in registeredEvents"
|
|
:key="registration.id"
|
|
class="py-3"
|
|
>
|
|
<template v-slot:prepend>
|
|
<v-avatar size="60" rounded="lg">
|
|
<v-img :src="registration.image" cover />
|
|
</v-avatar>
|
|
</template>
|
|
|
|
<v-list-item-title class="font-weight-medium">
|
|
{{ registration.title }}
|
|
</v-list-item-title>
|
|
<v-list-item-subtitle>
|
|
<div class="d-flex gap-3 mt-1">
|
|
<span><v-icon size="x-small">mdi-calendar</v-icon> {{ formatDate(registration.date) }}</span>
|
|
<span><v-icon size="x-small">mdi-clock-outline</v-icon> {{ registration.time }}</span>
|
|
<span><v-icon size="x-small">mdi-map-marker</v-icon> {{ registration.location }}</span>
|
|
</div>
|
|
</v-list-item-subtitle>
|
|
|
|
<template v-slot:append>
|
|
<div class="text-right">
|
|
<v-chip
|
|
color="success"
|
|
size="small"
|
|
variant="tonal"
|
|
class="mb-2"
|
|
>
|
|
<v-icon start size="x-small">mdi-check</v-icon>
|
|
Registered
|
|
</v-chip>
|
|
<div>
|
|
<v-btn
|
|
variant="text"
|
|
size="small"
|
|
color="error"
|
|
@click="cancelRegistration(registration)"
|
|
>
|
|
Cancel
|
|
</v-btn>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</v-list-item>
|
|
</v-list>
|
|
|
|
<!-- Empty State -->
|
|
<div v-if="registeredEvents.length === 0" class="text-center pa-8">
|
|
<v-icon size="64" color="grey-lighten-1">mdi-calendar-remove</v-icon>
|
|
<h3 class="text-h6 mt-4">No registered events</h3>
|
|
<p class="text-body-2 text-medium-emphasis">Browse upcoming events to find something interesting</p>
|
|
</div>
|
|
</v-card>
|
|
</v-col>
|
|
</v-row>
|
|
</v-window-item>
|
|
|
|
<!-- Past Events Tab -->
|
|
<v-window-item value="past">
|
|
<v-row>
|
|
<v-col cols="12">
|
|
<v-timeline side="end" density="compact">
|
|
<v-timeline-item
|
|
v-for="event in pastEvents"
|
|
:key="event.id"
|
|
dot-color="grey"
|
|
size="small"
|
|
>
|
|
<template v-slot:opposite>
|
|
<div class="text-caption text-medium-emphasis">
|
|
{{ formatDate(event.date) }}
|
|
</div>
|
|
</template>
|
|
|
|
<v-card elevation="1">
|
|
<v-card-title class="text-h6">{{ event.title }}</v-card-title>
|
|
<v-card-text>
|
|
<p class="text-body-2 mb-2">{{ event.description }}</p>
|
|
<div class="text-caption text-medium-emphasis">
|
|
<v-icon size="x-small">mdi-account-group</v-icon>
|
|
{{ event.attendees }} attendees
|
|
</div>
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-btn
|
|
variant="text"
|
|
size="small"
|
|
color="error"
|
|
@click="viewEventPhotos(event)"
|
|
>
|
|
View Photos
|
|
</v-btn>
|
|
<v-btn
|
|
variant="text"
|
|
size="small"
|
|
@click="viewEventDetails(event)"
|
|
>
|
|
View Details
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-timeline-item>
|
|
</v-timeline>
|
|
|
|
<!-- Empty State -->
|
|
<v-card v-if="pastEvents.length === 0" class="text-center pa-8" elevation="0">
|
|
<v-icon size="64" color="grey-lighten-1">mdi-history</v-icon>
|
|
<h3 class="text-h6 mt-4">No past events</h3>
|
|
<p class="text-body-2 text-medium-emphasis">Past events will appear here</p>
|
|
</v-card>
|
|
</v-col>
|
|
</v-row>
|
|
</v-window-item>
|
|
</v-window>
|
|
|
|
<!-- Event Details Dialog -->
|
|
<v-dialog v-model="detailsDialog" max-width="600">
|
|
<v-card v-if="selectedEvent">
|
|
<v-img
|
|
:src="selectedEvent.image"
|
|
height="200"
|
|
cover
|
|
/>
|
|
<v-card-title>{{ selectedEvent.title }}</v-card-title>
|
|
<v-card-text>
|
|
<v-chip
|
|
:color="getCategoryColor(selectedEvent.category)"
|
|
size="small"
|
|
variant="tonal"
|
|
class="mb-3"
|
|
>
|
|
{{ selectedEvent.category }}
|
|
</v-chip>
|
|
|
|
<p class="mb-4">{{ selectedEvent.fullDescription || selectedEvent.description }}</p>
|
|
|
|
<v-list density="compact">
|
|
<v-list-item>
|
|
<template v-slot:prepend>
|
|
<v-icon>mdi-calendar</v-icon>
|
|
</template>
|
|
<v-list-item-title>{{ formatDate(selectedEvent.date) }}</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item>
|
|
<template v-slot:prepend>
|
|
<v-icon>mdi-clock-outline</v-icon>
|
|
</template>
|
|
<v-list-item-title>{{ selectedEvent.time }}</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item>
|
|
<template v-slot:prepend>
|
|
<v-icon>mdi-map-marker</v-icon>
|
|
</template>
|
|
<v-list-item-title>{{ selectedEvent.location }}</v-list-item-title>
|
|
</v-list-item>
|
|
<v-list-item>
|
|
<template v-slot:prepend>
|
|
<v-icon>mdi-account-group</v-icon>
|
|
</template>
|
|
<v-list-item-title>{{ selectedEvent.attendees }} / {{ selectedEvent.capacity }} attendees</v-list-item-title>
|
|
</v-list-item>
|
|
</v-list>
|
|
</v-card-text>
|
|
<v-card-actions>
|
|
<v-spacer />
|
|
<v-btn variant="text" @click="detailsDialog = false">Close</v-btn>
|
|
<v-btn
|
|
color="error"
|
|
variant="flat"
|
|
:disabled="selectedEvent.attendees >= selectedEvent.capacity"
|
|
@click="registerForEvent(selectedEvent)"
|
|
>
|
|
Register
|
|
</v-btn>
|
|
</v-card-actions>
|
|
</v-card>
|
|
</v-dialog>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
definePageMeta({
|
|
layout: 'member',
|
|
middleware: 'member'
|
|
});
|
|
|
|
// State
|
|
const tab = ref('upcoming');
|
|
const searchQuery = ref('');
|
|
const selectedCategory = ref(null);
|
|
const selectedMonth = ref(null);
|
|
const detailsDialog = ref(false);
|
|
const selectedEvent = ref(null);
|
|
|
|
// Filter options
|
|
const categories = ref([
|
|
'Networking',
|
|
'Workshop',
|
|
'Social',
|
|
'Cultural',
|
|
'Business',
|
|
'Charity'
|
|
]);
|
|
|
|
const months = ref([
|
|
'January',
|
|
'February',
|
|
'March',
|
|
'April',
|
|
'May',
|
|
'June',
|
|
'July',
|
|
'August',
|
|
'September',
|
|
'October',
|
|
'November',
|
|
'December'
|
|
]);
|
|
|
|
// Mock event data
|
|
const upcomingEvents = ref([
|
|
{
|
|
id: 1,
|
|
title: 'Monaco Business Networking',
|
|
description: 'Connect with fellow Monaco entrepreneurs and business leaders',
|
|
fullDescription: 'Join us for an evening of networking with Monaco\'s business community. This event brings together entrepreneurs, executives, and professionals from various industries.',
|
|
category: 'Networking',
|
|
date: '2024-02-15',
|
|
time: '6:00 PM - 8:00 PM',
|
|
location: 'Monaco Yacht Club',
|
|
image: 'https://picsum.photos/400/300?random=1',
|
|
attendees: 45,
|
|
capacity: 100
|
|
},
|
|
{
|
|
id: 2,
|
|
title: 'Digital Marketing Workshop',
|
|
description: 'Learn the latest digital marketing strategies and techniques',
|
|
category: 'Workshop',
|
|
date: '2024-02-22',
|
|
time: '2:00 PM - 5:00 PM',
|
|
location: 'Conference Center',
|
|
image: 'https://picsum.photos/400/300?random=2',
|
|
attendees: 28,
|
|
capacity: 50
|
|
},
|
|
{
|
|
id: 3,
|
|
title: 'Annual Gala Dinner',
|
|
description: 'Celebrate the year with an elegant evening of dining and entertainment',
|
|
category: 'Social',
|
|
date: '2024-03-05',
|
|
time: '7:00 PM - 11:00 PM',
|
|
location: 'Hotel Hermitage',
|
|
image: 'https://picsum.photos/400/300?random=3',
|
|
attendees: 120,
|
|
capacity: 150
|
|
},
|
|
{
|
|
id: 4,
|
|
title: 'Monaco Grand Prix Viewing',
|
|
description: 'Watch the Monaco Grand Prix from our exclusive viewing area',
|
|
category: 'Social',
|
|
date: '2024-05-26',
|
|
time: '12:00 PM - 6:00 PM',
|
|
location: 'Private Terrace',
|
|
image: 'https://picsum.photos/400/300?random=4',
|
|
attendees: 75,
|
|
capacity: 75
|
|
}
|
|
]);
|
|
|
|
const registeredEvents = ref([
|
|
{
|
|
id: 1,
|
|
title: 'Monaco Business Networking',
|
|
date: '2024-02-15',
|
|
time: '6:00 PM',
|
|
location: 'Monaco Yacht Club',
|
|
image: 'https://picsum.photos/400/300?random=1'
|
|
},
|
|
{
|
|
id: 3,
|
|
title: 'Annual Gala Dinner',
|
|
date: '2024-03-05',
|
|
time: '7:00 PM',
|
|
location: 'Hotel Hermitage',
|
|
image: 'https://picsum.photos/400/300?random=3'
|
|
}
|
|
]);
|
|
|
|
const pastEvents = ref([
|
|
{
|
|
id: 5,
|
|
title: 'New Year Celebration',
|
|
description: 'Welcomed 2024 with a spectacular celebration',
|
|
date: '2024-01-01',
|
|
attendees: 200
|
|
},
|
|
{
|
|
id: 6,
|
|
title: 'Investment Seminar',
|
|
description: 'Expert insights on investment strategies for 2024',
|
|
date: '2024-01-15',
|
|
attendees: 65
|
|
}
|
|
]);
|
|
|
|
// Methods
|
|
const formatDate = (dateString: string) => {
|
|
return new Date(dateString).toLocaleDateString('en-US', {
|
|
weekday: 'long',
|
|
year: 'numeric',
|
|
month: 'long',
|
|
day: 'numeric'
|
|
});
|
|
};
|
|
|
|
const getCategoryColor = (category: string) => {
|
|
const colors: Record<string, string> = {
|
|
'Networking': 'blue',
|
|
'Workshop': 'purple',
|
|
'Social': 'green',
|
|
'Cultural': 'orange',
|
|
'Business': 'indigo',
|
|
'Charity': 'pink'
|
|
};
|
|
return colors[category] || 'grey';
|
|
};
|
|
|
|
const resetFilters = () => {
|
|
searchQuery.value = '';
|
|
selectedCategory.value = null;
|
|
selectedMonth.value = null;
|
|
};
|
|
|
|
const viewEventDetails = (event: any) => {
|
|
selectedEvent.value = event;
|
|
detailsDialog.value = true;
|
|
};
|
|
|
|
const registerForEvent = (event: any) => {
|
|
console.log('Registering for event:', event.title);
|
|
// Add to registered events
|
|
if (!registeredEvents.value.find(e => e.id === event.id)) {
|
|
registeredEvents.value.push({
|
|
id: event.id,
|
|
title: event.title,
|
|
date: event.date,
|
|
time: event.time,
|
|
location: event.location,
|
|
image: event.image
|
|
});
|
|
}
|
|
detailsDialog.value = false;
|
|
};
|
|
|
|
const cancelRegistration = (event: any) => {
|
|
console.log('Canceling registration for:', event.title);
|
|
const index = registeredEvents.value.findIndex(e => e.id === event.id);
|
|
if (index > -1) {
|
|
registeredEvents.value.splice(index, 1);
|
|
}
|
|
};
|
|
|
|
const viewEventPhotos = (event: any) => {
|
|
console.log('Viewing photos for:', event.title);
|
|
};
|
|
</script>
|
|
|
|
<style scoped>
|
|
.gap-3 {
|
|
gap: 0.75rem;
|
|
}
|
|
</style> |