126 lines
3.3 KiB
Vue
126 lines
3.3 KiB
Vue
<template>
|
|
<div v-if="shouldShowBanner" class="w-full">
|
|
<div
|
|
:class="[
|
|
'backdrop-blur-sm border rounded-lg p-4 flex items-start gap-4',
|
|
statusConfig.bgColor,
|
|
statusConfig.borderColor,
|
|
]"
|
|
>
|
|
<Icon
|
|
:name="statusConfig.icon"
|
|
:class="['w-5 h-5 flex-shrink-0 mt-0.5', statusConfig.textColor]"
|
|
/>
|
|
|
|
<div class="flex-1 min-w-0">
|
|
<h3 :class="['font-semibold mb-1', statusConfig.textColor]">
|
|
{{ statusConfig.label }}
|
|
</h3>
|
|
<p :class="['text-sm', statusConfig.textColor, 'opacity-90']">
|
|
{{ bannerMessage }}
|
|
</p>
|
|
</div>
|
|
|
|
<div class="flex items-center gap-2 flex-shrink-0">
|
|
<!-- Payment button for pending payment status -->
|
|
<UButton
|
|
v-if="isPendingPayment && nextAction"
|
|
:color="getButtonColor(nextAction.color)"
|
|
size="sm"
|
|
:loading="isProcessingPayment"
|
|
@click="handleActionClick"
|
|
class="whitespace-nowrap"
|
|
>
|
|
{{ isProcessingPayment ? "Processing..." : nextAction.label }}
|
|
</UButton>
|
|
|
|
<!-- Link button for other actions -->
|
|
<NuxtLink
|
|
v-else-if="nextAction && nextAction.link"
|
|
:to="nextAction.link"
|
|
:class="[
|
|
'px-4 py-2 rounded-lg font-medium text-sm whitespace-nowrap transition-all',
|
|
getActionButtonClass(nextAction.color),
|
|
]"
|
|
>
|
|
{{ nextAction.label }}
|
|
</NuxtLink>
|
|
|
|
<button
|
|
v-if="dismissible"
|
|
@click="isDismissed = true"
|
|
class="text-ghost-400 hover:text-ghost-200 transition-colors"
|
|
:aria-label="`Dismiss ${statusConfig.label} banner`"
|
|
>
|
|
<Icon name="heroicons:x-mark" class="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script setup>
|
|
const props = defineProps({
|
|
dismissible: {
|
|
type: Boolean,
|
|
default: true,
|
|
},
|
|
compact: {
|
|
type: Boolean,
|
|
default: false,
|
|
},
|
|
});
|
|
|
|
const {
|
|
isPendingPayment,
|
|
isSuspended,
|
|
isCancelled,
|
|
statusConfig,
|
|
getNextAction,
|
|
getBannerMessage,
|
|
} = useMemberStatus();
|
|
const { completePayment, isProcessingPayment } = useMemberPayment();
|
|
|
|
const isDismissed = ref(false);
|
|
|
|
// Handle action button click
|
|
const handleActionClick = async () => {
|
|
if (isPendingPayment.value) {
|
|
try {
|
|
await completePayment();
|
|
} catch (error) {
|
|
console.error("Payment failed:", error);
|
|
}
|
|
}
|
|
};
|
|
|
|
// Map color names to UButton color props
|
|
const getButtonColor = (color) => {
|
|
const colorMap = {
|
|
orange: "orange",
|
|
blue: "blue",
|
|
gray: "gray",
|
|
};
|
|
return colorMap[color] || "blue";
|
|
};
|
|
|
|
// Only show banner if status is not active
|
|
const shouldShowBanner = computed(() => {
|
|
if (isDismissed.value) return false;
|
|
return isPendingPayment.value || isSuspended.value || isCancelled.value;
|
|
});
|
|
|
|
const bannerMessage = computed(() => getBannerMessage());
|
|
const nextAction = computed(() => getNextAction());
|
|
|
|
// Button styling based on color
|
|
const getActionButtonClass = (color) => {
|
|
const baseClass = "hover:scale-105 active:scale-95";
|
|
const colorClasses = {
|
|
orange: "bg-orange-600 text-white hover:bg-orange-700",
|
|
blue: "bg-blue-600 text-white hover:bg-blue-700",
|
|
gray: "bg-ghost-700 text-ghost-100 hover:bg-ghost-600",
|
|
};
|
|
return `${baseClass} ${colorClasses[color] || colorClasses.blue}`;
|
|
};
|
|
</script>
|