yunlonggong's picture
Initial project upload
1b44660
<script setup lang="ts">
const COOKIE_NAME = 'meridian_subscribed';
const LEGACY_STORAGE_KEY = 'meridian_subscribed';
// Subscription state
const email = ref('');
const isSubmitting = ref(false);
const errorMessage = ref('');
const hasSubscribed = useCookie<string | null>(COOKIE_NAME);
// Migrate old localStorage data if it exists
onMounted(() => {
const legacyValue = localStorage.getItem(LEGACY_STORAGE_KEY);
if (legacyValue === 'true' && !hasSubscribed.value) {
hasSubscribed.value = 'true';
localStorage.removeItem(LEGACY_STORAGE_KEY);
}
});
/**
* Subscription form handlers
*/
const handleSubmit = async () => {
isSubmitting.value = true;
errorMessage.value = '';
try {
const response = await $fetch('/api/subscribe', {
method: 'POST',
body: { email: email.value },
});
if (!response.success) {
throw new Error(response.message || 'Failed to subscribe');
}
email.value = '';
hasSubscribed.value = 'true';
} catch (error: unknown) {
errorMessage.value = error instanceof Error ? error.message : 'Something went wrong, please try again.';
console.error('Subscription error:', error);
} finally {
isSubmitting.value = false;
}
};
const handleChangeEmail = () => {
hasSubscribed.value = null;
errorMessage.value = '';
};
</script>
<template>
<div>
<div v-if="!hasSubscribed" class="gap-2 text-sm flex flex-col items-center">
<p>Want this brief in your inbox? Sign up for updates</p>
<form class="flex flex-col group max-w-md mx-auto" @submit.prevent="handleSubmit">
<div class="flex border border-zinc-300">
<input
v-model="email"
type="email"
placeholder="[email protected]"
required
:aria-invalid="!!errorMessage"
aria-describedby="subscription-error"
class="flex-grow px-4 py-2 focus:outline-zinc-400"
/>
<button
type="submit"
class="bg-zinc-300 text-zinc-700 hover:cursor-pointer px-4 py-2 font-medium hover:bg-zinc-400 dark:hover:bg-zinc-400 transition-colors"
:disabled="isSubmitting"
>
{{ isSubmitting ? 'Sending...' : 'Subscribe' }}
</button>
</div>
<div v-if="errorMessage" id="subscription-error" class="text-red-600 text-xs mt-2" role="alert">
{{ errorMessage }}
</div>
</form>
</div>
<div v-else class="text-center text-sm">
<p>You're subscribed to our updates!</p>
<button class="underline mt-2 text-xs" @click="handleChangeEmail">Change email</button>
</div>
</div>
</template>