Skip to content

Commit

Permalink
Account page
Browse files Browse the repository at this point in the history
Fixes #96
  • Loading branch information
Perdolique committed Nov 24, 2024
1 parent 35149cf commit 9830990
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 14 deletions.
44 changes: 44 additions & 0 deletions app/components/IconTitle.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
<template>
<div :class="$style.component">
<div :class="$style.iconWrapper">
<Icon
:name="icon"
size="20px"
/>
</div>

<PerdHeading :level="level">
<slot />
</PerdHeading>
</div>
</template>

<script lang="ts" setup>
import PerdHeading from '~/components/PerdHeading.vue'
interface Props {
readonly icon: string;
readonly level: InstanceType<typeof PerdHeading>['level'];
}
defineProps<Props>()
</script>

<style module>
.component {
display: flex;
align-items: center;
column-gap: var(--spacing-12);
}
.iconWrapper {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: var(--border-radius-12);
background: var(--secondary-100);
color: var(--secondary-500);
}
</style>
7 changes: 7 additions & 0 deletions app/components/PageHeader.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@
</button>
</template>

<OptionButton
icon="tabler:user-circle"
@click="navigateTo('/account')"
>
Account
</OptionButton>

<OptionButton
icon="tabler:logout"
@click="removeAuthSession"
Expand Down
14 changes: 14 additions & 0 deletions app/components/PerdCard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<template>
<div :class="$style.component">
<slot />
</div>
</template>

<style module>
.component {
background-color: var(--background-50);
border-radius: var(--border-radius-16);
padding: var(--spacing-24);
border: 1px solid var(--background-100);
}
</style>
148 changes: 148 additions & 0 deletions app/pages/account.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
<template>
<PageContent page-title="Account">
<div :class="$style.content">
<PerdCard :class="$style.card">
<IconTitle
icon="tabler:user"
:level="2"
>
Profile Information
</IconTitle>

<div :class="$style.infoBlock">
<div :class="$style.infoItem">
<span :class="$style.label">
User ID
</span>

<span :class="$style.value">
{{ user.userId }}
</span>
</div>

<div :class="$style.infoItem">
<span :class="$style.label">
Role
</span>

<span :class="$style.value">
{{ role }}
</span>
</div>
</div>
</PerdCard>

<PerdCard :class="$style.card">
<IconTitle
icon="tabler:alert-triangle"
:level="2"
>
Danger Zone
</IconTitle>

<PerdButton
secondary
icon="tabler:trash"
@click="onDeleteClick"
>
Delete Account
</PerdButton>
</PerdCard>
</div>

<ConfirmationDialog
v-model="showDeleteModal"
header-text="Delete account"
confirm-button-text="Delete account"
@confirm="handleDeleteAccount"
>
Are you sure you want to delete your account? This action cannot be undone.
</ConfirmationDialog>
</PageContent>
</template>

<script lang="ts" setup>
import ConfirmationDialog from '~/components/dialogs/ConfirmationDialog.vue'
import IconTitle from '~/components/IconTitle.vue'
import PageContent from '~/components/layout/PageContent.vue'
import PerdButton from '~/components/PerdButton.vue'
import PerdCard from '~/components/PerdCard.vue'
definePageMeta({
layout: 'page'
})
const { user, resetAuthentication } = useUserStore()
const { showErrorToast } = useApiErrorToast()
const { addToast } = useToaster()
const showDeleteModal = ref(false)
const isDeleting = ref(false)
const role = computed(() => user.value.isAdmin ? 'Admin' : 'User')
function onDeleteClick() {
showDeleteModal.value = true
}
async function handleDeleteAccount() {
if (isDeleting.value) {
return
}
try {
isDeleting.value = true
await $fetch('/api/account', {
method: 'DELETE'
})
addToast({
title: 'Account deleted',
message: 'Bye! 👋'
})
resetAuthentication()
await navigateTo({
path: '/login'
})
} catch (error) {
showErrorToast(error, 'Failed to delete account')
} finally {
isDeleting.value = false
}
}
</script>

<style module>
.content {
display: grid;
row-gap: var(--spacing-24);
}
.card {
display: grid;
row-gap: var(--spacing-24);
justify-content: start;
}
.infoBlock {
display: grid;
row-gap: var(--spacing-16);
}
.infoItem {
display: grid;
row-gap: var(--spacing-8);
justify-content: start;
}
.label {
font-size: var(--font-size-16);
font-weight: var(--font-weight-medium);
}
.value {
font-size: var(--font-size-14);
color: var(--text-color-secondary);
}
</style>
17 changes: 4 additions & 13 deletions app/pages/index.vue
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
<template>
<div :class="$style.component">
<div>
Hello, {{ user.userId }}
</div>

<div>
Your admin status is: {{ user.isAdmin }}
</div>
🐕💨
</div>
</template>

<script lang="ts" setup>
definePageMeta({
layout: 'page'
})
const { user } = useUserStore()
</script>

<style module>
.component {
display: grid;
justify-content: center;
gap: var(--spacing-16);
padding-top: var(--spacing-32);
text-align: center;
font-size: 64px;
padding-top: 32px;
}
</style>
15 changes: 15 additions & 0 deletions server/api/account/index.delete.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { and, eq } from 'drizzle-orm'

export default defineEventHandler(async (event) => {
const userId = await validateSessionUser(event)

await event.context.db
.delete(tables.users)
.where(
and(
eq(tables.users.id, userId)
)
)

setResponseStatus(event, 204)
})
2 changes: 1 addition & 1 deletion server/database/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ export const equipment = pgTable('equipment', {
check(
'equipment_description_check',
sql.raw(`char_length(description) <= ${limits.maxEquipmentDescriptionLength}`)
),
)
])

/**
Expand Down

0 comments on commit 9830990

Please sign in to comment.