UserProfileHeader.vue 9.38 KB
<script lang="ts" setup>
import type { ProfileHeader } from '@db/dstipro/profile/types'
import profileImg from '@images/avatars/avatar-1.png'
import coverImg from '@images/pages/user-profile-header-bg.png'
import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration'
import PersonAvatar from '@/layouts/components/PersonAvatar.vue'
import keycloakInstance from '@/keycloak'
import { useKeycloakStore } from '@/@core/stores/keycloakStore'

dayjs.extend(duration)

const profileHeaderData = ref<ProfileHeader | null>(null)

const keycloakStore = useKeycloakStore()

// Gunakan computed agar selalu reaktif
const isAuthenticated = computed(() => keycloakStore.authenticated)

function login() {
  keycloakInstance.login()
}

const logoutUrl = ref(
  'https://login.ui.ac.id/realms/main/protocol/openid-connect/logout?client_id=vueplayground',
)

const logoutUser = () => {
  // Use window.location.origin for a dynamic base URL
  const redirectUri = window.location.origin

  // Redirect to logout URL with the dynamic origin
  window.location.href = `${logoutUrl.value}&post_logout_redirect_uri=${redirectUri}/login`
}

const items = ref<Record<string, any>>({})
const loading = ref(false)
const errordata = ref('')
const isBirthday = ref(false)

async function getData() {
  loading.value = true
  errordata.value = ''
  try {
    const apiEndpoint = 'https://api.ui.ac.id/me'

    const response = await fetch(apiEndpoint, {
      headers: {
        Authorization: `Bearer ${keycloakStore.accessToken}`,
      },
    })

    if (!response.ok)
      throw new Error('Gagal mengambil data')
    const dataku = await response.json()

    items.value = dataku
  }
  catch (err: any) {
    errordata.value = err.message || 'Terjadi kesalahan saat mengambil data'
  }
  finally {
    loading.value = false
  }
}

// Fetch data from API
onMounted(() => {
  getData()
})

// Fetch profile header
onMounted(() => {
  profileHeaderData.value = {
    coverImg,
    designation: 'UX Designer',
    fullName: 'Abdullah',
    joiningDate: 'April 2021',
    location: 'Madinah',
    profileImg,
  }
})

// Menentukan nilai tanggal lahir berdasarkan kondisi `civitas`
const tglLahir = computed(() => {
  return keycloakStore.civitas === 'mahasiswa' ? items.value?.TGL_LAHIR : items.value?.tgl_lahir
})

// Cek apakah hari ini adalah ulang tahun
function checkBirthday() {
  if (!tglLahir.value) {
    isBirthday.value = false

    return
  }

  const birthDate = dayjs(tglLahir.value)
  const today = dayjs()

  isBirthday.value = birthDate.format('MM-DD') === today.format('MM-DD')
}

// Panggil `checkBirthday` saat `tglLahir` berubah
watch(tglLahir, checkBirthday)

// Jalankan `checkBirthday` saat komponen dimuat
onMounted(checkBirthday)

// Fungsi untuk menghitung umur dalam tahun, bulan, dan hari
const umur = computed(() => {
  if (!tglLahir.value)
    return 'Data tidak tersedia'

  const birthDate = dayjs(tglLahir.value)
  if (!birthDate.isValid())
    return 'Format tanggal tidak valid'

  const today = dayjs()
  const diff = dayjs.duration(today.diff(birthDate))

  return `${diff.years()} tahun, ${diff.months()} bulan, ${diff.days()} hari`
})

// Fungsi untuk menghitung waktu menuju ulang tahun berikutnya
const ulangTahunBerikutnya = computed(() => {
  if (!tglLahir.value)
    return 'Data tidak tersedia'

  const birthDate = dayjs(tglLahir.value)
  if (!birthDate.isValid())
    return 'Format tanggal tidak valid'

  const today = dayjs()
  let nextBirthday = birthDate.year(today.year())

  // Jika ulang tahun sudah lewat tahun ini, ambil ulang tahun tahun depan
  if (nextBirthday.isBefore(today))
    nextBirthday = birthDate.year(today.year() + 1)

  const diff = dayjs.duration(nextBirthday.diff(today))

  return `${diff.months()} bulan, ${diff.days()} hari`
})
</script>

<template>
  <VCard v-if="profileHeaderData">
    <!-- Efek animasi Happy Birthday -->
    <VAlert
      v-if="isBirthday"
      type="info"
      class="happy-birthday"
    >
      🎉 Selamat Ulang Tahun! 🎉<br>
      🥳🎂🎈<br>
      🥳 Semoga harimu menyenangkan! 🥳
    </VAlert>

    <VImg
      :src="profileHeaderData.coverImg"
      min-height="125"
      max-height="250"
      cover
    />

    <VCardText
      v-if="isAuthenticated"
      class="d-flex align-bottom flex-sm-row flex-column justify-center gap-x-6"
    >
      <div class="d-flex h-0">
        <VAvatar
          rounded
          size="130"
          :image="profileHeaderData.profileImg"
          class="user-profile-avatar mx-auto"
        >
          <PersonAvatar style="block-size: 120px; inline-size: 120px;" />
        </VAvatar>
      </div>

      <div class="user-profile-info w-100 mt-16 pt-6 pt-sm-0 mt-sm-0">
        <h4 class="text-h4 text-center text-sm-start mb-2">
          {{ keycloakStore.name }}
        </h4>

        <div class="d-flex align-center justify-center justify-sm-space-between flex-wrap gap-4">
          <div class="d-flex flex-wrap justify-center justify-sm-start flex-grow-1 gap-6">
            <div class="d-flex align-center gap-x-2">
              <VIcon
                size="24"
                icon="ri-id-card-line"
              />
              <div class="text-body-1 font-weight-medium">
                <!-- {{ keycloakStore.civitas[0].toUpperCase() + keycloakStore.civitas.slice(1) }} -->
                {{ keycloakStore.civitas == 'dosen' ? 'STAF' : keycloakStore.civitas.toUpperCase() }}
              </div>
            </div>

            <div
              v-if="!isBirthday"
              class="d-flex align-center gap-x-2"
            >
              <VIcon
                size="24"
                icon="ri-cake-2-line"
              />
              <div class="text-body-1 font-weight-medium">
                <!-- {{ keycloakStore.civitas == 'mahasiswa' ? items?.TGL_LAHIR : items?.tgl_lahir }} -->
                {{ ulangTahunBerikutnya }}
              </div>
            </div>

            <div
              v-if="isBirthday"
              class="d-flex align-center gap-x-2"
            >
              <VIcon
                size="24"
                icon="ri-gift-line"
              />
              <div class="text-body-1 font-weight-medium">
                {{ umur }}
              </div>
            </div>

            <!-- tombol test aksi ultah -->
            <div class="d-flex align-center gap-x-2">
              <VBtn @click="isBirthday = true">
                <VIcon
                  size="24"
                  icon="ri-hand-heart-line"
                />
              </VBtn>
            </div>
          </div>

          <VBtn prepend-icon="ri-user-follow-line">
            Connected
          </VBtn>

          <VBtn
            class="bg-error"
            prepend-icon="ri-logout-box-r-line"
            @click="logoutUser"
          >
            Logout
          </VBtn>
        </div>
      </div>
    </VCardText>

    <VCardText
      v-else
      class="d-flex align-bottom flex-sm-row flex-column justify-center gap-x-6"
    >
      <div class="d-flex h-0">
        <VAvatar
          rounded
          size="130"
          :image="profileHeaderData.profileImg"
          class="user-profile-avatar mx-auto"
        >
          <VImg
            :src="profileHeaderData.profileImg"
            height="120"
            width="120"
          />
        </VAvatar>
      </div>

      <div class="user-profile-info w-100 mt-16 pt-6 pt-sm-0 mt-sm-0">
        <h4 class="text-h4 text-center text-sm-start mb-2">
          {{ profileHeaderData.fullName }}
        </h4>

        <div class="d-flex align-center justify-center justify-sm-space-between flex-wrap gap-4">
          <div class="d-flex flex-wrap justify-center justify-sm-start flex-grow-1 gap-6">
            <div class="d-flex align-center gap-x-2">
              <VIcon
                size="24"
                icon="ri-palette-line"
              />
              <div class="text-body-1 font-weight-medium">
                {{ profileHeaderData.designation }}
              </div>
            </div>

            <div class="d-flex align-center gap-x-2">
              <VIcon
                size="24"
                icon="ri-map-pin-line"
              />
              <div class="text-body-1 font-weight-medium">
                {{ profileHeaderData.location }}
              </div>
            </div>

            <div class="d-flex align-center gap-x-2">
              <VIcon
                size="24"
                icon="ri-calendar-line"
              />
              <div class="text-body-1 font-weight-medium">
                {{ profileHeaderData.joiningDate }}
              </div>
            </div>
          </div>

          <VBtn
            class="bg-error"
            prepend-icon="ri-user-follow-line"
          >
            Not Connected
          </VBtn>

          <VBtn
            class="bg-warning"
            prepend-icon="ri-login-box-line"
            @click="login"
          >
            Login
          </VBtn>
        </div>
      </div>
    </VCardText>
  </VCard>
</template>

<style lang="scss">
.user-profile-avatar {
  border: 5px solid rgb(var(--v-theme-surface));
  background-color: rgb(var(--v-theme-surface)) !important;
  inset-block-start: -3rem;

  .v-img__img {
    border-radius: 0.375rem;
  }
}

/* Animasi Happy Birthday */
.happy-birthday {
  animation: bounce 1.5s infinite alternate ease-in-out;
  font-size: 1.5rem;
  font-weight: bold;
  text-align: center;
}

@keyframes bounce {
  from {
    transform: translateY(0);
  }

  to {
    transform: translateY(-10px);
  }
}
</style>