Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 154 additions & 48 deletions resources/js/pages/Profile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ import {
Sparkles,
ArrowRight,
Mail,
AlertTriangle,
ChevronDown,
} from 'lucide-vue-next';
import { computed } from 'vue';
import { computed, ref } from 'vue';

const props = defineProps({
user: Object,
Expand All @@ -25,6 +27,9 @@ const hasNoRole = computed(() => {
return !roles || roles.length === 0;
});

const showAdvancedSettings = ref(false);
const showConfirmModal = ref(false);

const form = useForm({
_method: 'PUT',
name: user.value?.name || '',
Expand All @@ -38,6 +43,19 @@ const form = useForm({
receive_emails: user.value?.receive_emails ?? true,
});

const handleEmailToggle = () => {
if (form.receive_emails) {
showConfirmModal.value = true;
} else {
form.receive_emails = true;
}
};

const confirmDisable = () => {
form.receive_emails = false;
showConfirmModal.value = false;
};

const submitForm = () => {
form.post('/profile', {
preserveScroll: true,
Expand Down Expand Up @@ -451,62 +469,96 @@ const submitForm = () => {
</div>
</div>

<!-- Email Preferences Card -->
<!-- Advanced Notification Preferences (Collapsible Dropdown) -->
<div
class="rounded-2xl border border-slate-200/80 bg-white p-6 shadow-xs sm:p-8 dark:border-gray-700 dark:bg-gray-900"
class="rounded-xl border border-slate-200/60 bg-slate-50/40 p-3 sm:p-4 dark:border-gray-800 dark:bg-gray-900/30"
>
<div
class="mb-6 flex items-center gap-3 border-b border-slate-100 pb-4 dark:border-gray-800"
<button
type="button"
@click="showAdvancedSettings = !showAdvancedSettings"
class="flex w-full items-center justify-between text-left text-xs font-medium text-slate-500 hover:text-slate-700 transition dark:text-gray-400 dark:hover:text-gray-200"
>
<div
class="flex h-9 w-9 items-center justify-center rounded-xl bg-amber-50 text-amber-600 dark:bg-amber-500/10 dark:text-amber-400"
>
<Mail class="h-5 w-5" />
</div>
<div>
<h2
class="text-base font-semibold text-slate-900 dark:text-gray-100"
<div class="flex items-center gap-2">
<span>Advanced Notification Preferences</span>
<span
v-if="!form.receive_emails"
class="inline-flex items-center rounded bg-amber-100 px-1.5 py-0.5 text-[10px] font-semibold text-amber-700 dark:bg-amber-950/60 dark:text-amber-300"
>
Email Preferences
</h2>
<p class="text-xs text-slate-500 dark:text-gray-400">
Manage what email announcements and updates you
receive.
</p>
Updates Paused
</span>
</div>
</div>
<ChevronDown
class="h-3.5 w-3.5 text-slate-400 transition-transform duration-200 dark:text-gray-500"
:class="{ 'rotate-180': showAdvancedSettings }"
/>
</button>

<div
class="flex items-center justify-between gap-4 rounded-xl border border-slate-100 bg-slate-50/70 p-4 dark:border-gray-800 dark:bg-gray-950/50"
<transition
enter-active-class="transition duration-200 ease-out"
enter-from-class="opacity-0 -translate-y-1"
enter-to-class="opacity-100 translate-y-0"
leave-active-class="transition duration-150 ease-in"
leave-from-class="opacity-100 translate-y-0"
leave-to-class="opacity-0 -translate-y-1"
>
<div class="space-y-0.5">
<label
for="receive_emails"
class="cursor-pointer text-sm font-semibold text-slate-900 dark:text-gray-100"
>
Receive Broadcast Emails & Announcements
</label>
<p class="text-xs text-slate-500 dark:text-gray-400">
Stay up-to-date with new resources, study materials,
and platform announcements.
</p>
</div>

<label
class="relative inline-flex shrink-0 cursor-pointer items-center"
<div
v-if="showAdvancedSettings"
class="mt-3 border-t border-slate-200/50 pt-3 dark:border-gray-800/60"
>
<input
type="checkbox"
id="receive_emails"
v-model="form.receive_emails"
:disabled="form.processing"
class="peer sr-only"
/>
<div class="flex items-center justify-between gap-4">
<div class="space-y-0.5">
<div class="flex items-center gap-2">
<span class="text-xs font-medium text-slate-700 dark:text-gray-300">
Essential study updates & announcements
</span>
<span
class="rounded bg-slate-200/60 px-1.5 py-0.5 text-[10px] font-medium text-slate-600 dark:bg-gray-800 dark:text-gray-400"
>
Recommended
</span>
</div>
<p class="text-[11px] text-slate-500 dark:text-gray-400">
Receive notifications for syllabus changes, study materials, and platform alerts.
</p>
</div>

<button
type="button"
@click="handleEmailToggle"
:disabled="form.processing"
class="relative inline-flex shrink-0 cursor-pointer items-center focus:outline-none"
>
<div
class="h-5 w-9 rounded-full transition-colors after:absolute after:top-[2px] after:left-[2px] after:h-4 after:w-4 after:rounded-full after:bg-white after:shadow-sm after:transition-all after:content-[''] dark:after:bg-gray-200"
:class="
form.receive_emails
? 'bg-slate-700 after:translate-x-4 dark:bg-gray-500'
: 'bg-slate-300 dark:bg-gray-700'
"
></div>
</button>
</div>

<!-- Dark Friction Warning if disabled -->
<div
class="peer h-6 w-11 rounded-full bg-slate-300 transition-colors peer-checked:bg-blue-600 peer-focus:ring-2 peer-focus:ring-blue-500/20 after:absolute after:top-[2px] after:left-[2px] after:h-5 after:w-5 after:rounded-full after:bg-white after:shadow-md after:transition-all after:content-[''] peer-checked:after:translate-x-full dark:bg-gray-700 dark:peer-checked:bg-blue-600 dark:after:bg-gray-200"
></div>
</label>
</div>
v-if="!form.receive_emails"
class="mt-3 flex items-start gap-2.5 rounded-lg border border-amber-200/80 bg-amber-50/80 p-2.5 text-xs text-amber-800 dark:border-amber-900/50 dark:bg-amber-950/30 dark:text-amber-300"
>
<AlertTriangle class="mt-0.5 h-3.5 w-3.5 shrink-0 text-amber-600 dark:text-amber-400" />
<div class="flex-1 text-[11px] leading-relaxed">
<span class="font-medium">You may miss critical updates:</span>
Disabling this will prevent you from receiving vital academic alerts, syllabus updates, and new study materials.
<button
type="button"
@click="form.receive_emails = true"
class="ml-1.5 font-semibold text-amber-700 underline hover:text-amber-900 dark:text-amber-300 dark:hover:text-amber-100"
>
Keep enabled
</button>
</div>
</div>
</div>
</transition>
</div>

<!-- Action Buttons -->
Expand All @@ -525,5 +577,59 @@ const submitForm = () => {
</button>
</div>
</form>

<!-- Confirmation Modal for turning off emails (Dark Friction UX) -->
<transition
enter-active-class="transition duration-200 ease-out"
enter-from-class="opacity-0 scale-95"
enter-to-class="opacity-100 scale-100"
leave-active-class="transition duration-150 ease-in"
leave-from-class="opacity-100 scale-100"
leave-to-class="opacity-0 scale-95"
>
<div
v-if="showConfirmModal"
class="fixed inset-0 z-50 flex items-center justify-center bg-slate-900/50 p-4 backdrop-blur-xs dark:bg-black/60"
>
<div
class="relative w-full max-w-md rounded-2xl border border-slate-200 bg-white p-6 shadow-xl dark:border-gray-800 dark:bg-gray-900"
>
<div class="flex items-start gap-4">
<div
class="flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-amber-50 text-amber-600 dark:bg-amber-500/10 dark:text-amber-400"
>
<AlertTriangle class="h-5 w-5" />
</div>
<div class="space-y-1">
<h3
class="text-base font-semibold text-slate-900 dark:text-gray-100"
>
Turn off essential announcements?
</h3>
<p class="text-xs leading-relaxed text-slate-500 dark:text-gray-400">
You will stop receiving critical syllabus announcements, new exam preparation materials, and platform alerts. We strongly recommend keeping this enabled.
</p>
</div>
</div>

<div class="mt-6 flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
<button
type="button"
@click="confirmDisable"
class="rounded-xl px-4 py-2 text-xs font-medium text-slate-400 hover:text-slate-600 dark:text-gray-500 dark:hover:text-gray-300 transition"
>
Yes, turn off anyway
</button>
<button
type="button"
@click="showConfirmModal = false"
class="inline-flex items-center justify-center rounded-xl bg-blue-600 px-5 py-2.5 text-xs font-semibold text-white shadow-xs hover:bg-blue-700 transition"
>
Keep Notifications Enabled
</button>
</div>
</div>
</div>
</transition>
</div>
</template>
Loading