Add global branding and implement member ID system
All checks were successful
Build And Push Image / docker (push) Successful in 3m2s

- Add MonacoUSA logo component with global header placement
- Implement member ID generation and migration system
- Create profile page and improve dashboard navigation
- Add member ID as payment reference in dues banner
- Enable support contact functionality with pre-filled email
This commit is contained in:
2025-08-10 16:49:23 +02:00
parent e33f32e15a
commit ecae3795ee
9 changed files with 986 additions and 9 deletions

View File

@@ -44,6 +44,21 @@
</v-col>
</v-row>
<v-divider class="my-2" />
<v-row dense>
<v-col cols="12">
<div class="text-caption font-weight-bold">Payment Reference:</div>
<div class="text-body-2 font-family-monospace" style="background-color: rgba(163, 21, 21, 0.1); padding: 8px; border-radius: 4px; border-left: 4px solid #a31515;">
{{ memberData?.member_id || 'Member ID pending' }}
</div>
<div class="text-caption text-medium-emphasis mt-1">
<v-icon size="small" class="mr-1">mdi-information-outline</v-icon>
Please include your member ID in the wire transfer reference for identification
</div>
</v-col>
</v-row>
<v-divider class="my-2" />
<div class="text-caption d-flex align-center">

View File

@@ -0,0 +1,159 @@
<template>
<div class="monaco-logo" :class="sizeClass">
<v-img
:src="logoSrc"
:width="logoWidth"
:height="logoHeight"
class="logo-img"
alt="MonacoUSA Logo"
:style="logoStyle"
/>
</div>
</template>
<script setup lang="ts">
interface Props {
size?: 'small' | 'medium' | 'large'
variant?: 'default' | 'white' | 'dark'
clickable?: boolean
}
const props = withDefaults(defineProps<Props>(), {
size: 'medium',
variant: 'default',
clickable: false
});
const emit = defineEmits<{
click: []
}>();
// Computed properties for responsive sizing
const sizeClass = computed(() => `monaco-logo--${props.size}`);
const logoSrc = computed(() => {
// Use the high-res Monaco flag image
return '/MONACOUSA-Flags_376x376.png';
});
const logoWidth = computed(() => {
switch (props.size) {
case 'small': return 32;
case 'medium': return 48;
case 'large': return 80;
default: return 48;
}
});
const logoHeight = computed(() => {
switch (props.size) {
case 'small': return 32;
case 'medium': return 48;
case 'large': return 80;
default: return 48;
}
});
const logoStyle = computed(() => {
const baseStyle: Record<string, string> = {
borderRadius: '8px',
boxShadow: '0 2px 8px rgba(0, 0, 0, 0.1)'
};
if (props.clickable) {
baseStyle.cursor = 'pointer';
baseStyle.transition = 'transform 0.2s ease-in-out, box-shadow 0.2s ease-in-out';
}
if (props.variant === 'white') {
baseStyle.backgroundColor = 'white';
baseStyle.padding = '4px';
} else if (props.variant === 'dark') {
baseStyle.backgroundColor = 'rgba(0, 0, 0, 0.1)';
baseStyle.padding = '4px';
}
return baseStyle;
});
// Handle click events
const handleClick = () => {
if (props.clickable) {
emit('click');
}
};
</script>
<style scoped>
.monaco-logo {
display: inline-flex;
align-items: center;
justify-content: center;
}
.monaco-logo--small {
min-width: 32px;
min-height: 32px;
}
.monaco-logo--medium {
min-width: 48px;
min-height: 48px;
}
.monaco-logo--large {
min-width: 80px;
min-height: 80px;
}
.logo-img {
object-fit: cover;
border-radius: inherit;
}
.monaco-logo:hover .logo-img {
transform: scale(1.05);
box-shadow: 0 4px 16px rgba(163, 21, 21, 0.2);
}
/* Ensure the logo maintains aspect ratio */
.v-img {
flex-shrink: 0;
}
/* Animation for clickable logos */
.monaco-logo[style*="cursor: pointer"]:hover {
transform: translateY(-2px);
}
.monaco-logo[style*="cursor: pointer"]:active {
transform: translateY(0);
}
/* Accessibility improvements */
@media (prefers-reduced-motion: reduce) {
.logo-img,
.monaco-logo {
transition: none !important;
transform: none !important;
}
}
/* High contrast mode support */
@media (prefers-contrast: high) {
.logo-img {
border: 2px solid currentColor;
}
}
/* Print styles */
@media print {
.monaco-logo {
box-shadow: none !important;
}
.logo-img {
transform: none !important;
}
}
</style>