feat(pages): create user profile page
This commit is contained in:
parent
8a042ec028
commit
a5ca37b4b7
228
pages/user/[id].vue
Normal file
228
pages/user/[id].vue
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import { format, formatDistanceToNow, formatRelative } from "date-fns";
|
||||||
|
import { IUser } from "~/models/user";
|
||||||
|
import { IStory } from "~/models/stories";
|
||||||
|
import { favourites } from "~/lib/client/listActions";
|
||||||
|
import singleStory from "~/components/listings/singleStory.vue";
|
||||||
|
import icon from "~/components/icon.vue";
|
||||||
|
import adminPanel from "~/components/profile/adminPanel.vue";
|
||||||
|
|
||||||
|
const rtr = useRoute();
|
||||||
|
const { data } = useAuth();
|
||||||
|
|
||||||
|
const { data: userInfo } = await useApiFetch<IUser>(`/user/${rtr.params.id}`);
|
||||||
|
if (userInfo === null) {
|
||||||
|
navigateTo("/");
|
||||||
|
}
|
||||||
|
const activeKey = ref("main");
|
||||||
|
const activeFavKey = ref("favs/stories");
|
||||||
|
const uLastVisit = Date.parse(
|
||||||
|
(userInfo.value?.lastVisit ||
|
||||||
|
userInfo.value?.lastLogin) as unknown as string,
|
||||||
|
);
|
||||||
|
|
||||||
|
const isSelf = userInfo.value?._id === parseInt(rtr.params.id as string);
|
||||||
|
|
||||||
|
console.log("rtr", rtr);
|
||||||
|
console.log("LVLVLVLVVLV", new Date(uLastVisit));
|
||||||
|
</script>
|
||||||
|
<template>
|
||||||
|
<a-card style="width: 100%">
|
||||||
|
<template #title>
|
||||||
|
<div style="height: fit-content">
|
||||||
|
<a-card-meta style="align-items: center; margin: 0.5em">
|
||||||
|
<template #avatar>
|
||||||
|
<a-avatar
|
||||||
|
:size="75"
|
||||||
|
:src="`/avatars/${userInfo?.profile.avatar}.png`"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
<template #title>
|
||||||
|
<a-typography-title :level="1" style="margin-top: 0.5em">
|
||||||
|
{{ userInfo!.username }}
|
||||||
|
</a-typography-title>
|
||||||
|
</template>
|
||||||
|
</a-card-meta>
|
||||||
|
</div>
|
||||||
|
<a-badge-ribbon color="#d03f5b" v-if="userInfo?.profile.isAdmin">
|
||||||
|
<template #text> Administrator </template>
|
||||||
|
</a-badge-ribbon>
|
||||||
|
</template>
|
||||||
|
<a-descriptions
|
||||||
|
:column="2"
|
||||||
|
:labelStyle="{ fontWeight: 'bold' }"
|
||||||
|
:colon="false"
|
||||||
|
>
|
||||||
|
<a-descriptions-item label="Last visit">
|
||||||
|
<div v-if="userInfo?.banned" style="color: red; font-weight: bold">
|
||||||
|
BANNED
|
||||||
|
</div>
|
||||||
|
<div v-else-if="userInfo?.profile.hidden">
|
||||||
|
<i>Unknown</i>
|
||||||
|
</div>
|
||||||
|
<div v-else>
|
||||||
|
<span>
|
||||||
|
{{ format(uLastVisit, "MM/dd/yyyy @ hh:mm:ss a") }}
|
||||||
|
</span>
|
||||||
|
<span style="margin-left: 0.6em">
|
||||||
|
({{ formatDistanceToNow(uLastVisit, { addSuffix: true }) }})
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="Website">
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
:href="`${
|
||||||
|
userInfo?.profile.website.startsWith('http') ? '' : 'http://'
|
||||||
|
}${userInfo?.profile.website}`"
|
||||||
|
>
|
||||||
|
{{ userInfo?.profile.website }}
|
||||||
|
</a>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="Blog/Journal">
|
||||||
|
<a
|
||||||
|
target="_blank"
|
||||||
|
:href="`${
|
||||||
|
userInfo?.profile.blog.startsWith('http') ? '' : 'http://'
|
||||||
|
}${userInfo?.profile.blog}`"
|
||||||
|
>
|
||||||
|
{{ userInfo?.profile.blog }}
|
||||||
|
</a>
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item label="Occupation">
|
||||||
|
{{ userInfo?.profile.occupation }}
|
||||||
|
</a-descriptions-item>
|
||||||
|
<a-descriptions-item
|
||||||
|
label="Email"
|
||||||
|
v-if="userInfo?.profile.showEmail || data?.user?.profile.isAdmin"
|
||||||
|
>
|
||||||
|
{{ userInfo?.email }}
|
||||||
|
</a-descriptions-item>
|
||||||
|
</a-descriptions>
|
||||||
|
<a-divider style="border: 1px solid #3e1560" />
|
||||||
|
<a-tabs centered v-model:active-key="activeKey">
|
||||||
|
<a-tab-pane key="main" tab="Profile">
|
||||||
|
<div v-html="userInfo?.profile.bio"></div>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="stories" tab="Stories">
|
||||||
|
<listings-stories :prefix="`/user/${$route.params.id}/stories`" />
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="favs" tab="Favourites">
|
||||||
|
<a-tabs centered v-model:active-key="activeFavKey">
|
||||||
|
<a-tab-pane key="favs/stories" tab="Stories">
|
||||||
|
<a-list
|
||||||
|
:pagination="{
|
||||||
|
defaultPageSize: 20,
|
||||||
|
total: userInfo?.favs.stories.length,
|
||||||
|
defaultCurrent: 1,
|
||||||
|
// onChange: pagiChange,
|
||||||
|
hideOnSinglePage: true,
|
||||||
|
showSizeChanger: false,
|
||||||
|
}"
|
||||||
|
:data-source="userInfo?.favs.stories"
|
||||||
|
item-layout="vertical"
|
||||||
|
>
|
||||||
|
<template #renderItem="{ item }">
|
||||||
|
<!-- {{ item.title }} -->
|
||||||
|
<a-row :gutter="[25, 0]" :align="'middle'">
|
||||||
|
<a-col :span="23">
|
||||||
|
<single-story :story="item" />
|
||||||
|
</a-col>
|
||||||
|
<a-col :span="1" v-if="isSelf">
|
||||||
|
<a
|
||||||
|
style="color: red"
|
||||||
|
@click="
|
||||||
|
() =>
|
||||||
|
favourites(
|
||||||
|
userInfo?.favs.stories || [],
|
||||||
|
item._id,
|
||||||
|
true,
|
||||||
|
'story',
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<icon istyle="regular" name="trash" color="#f00" />
|
||||||
|
</a>
|
||||||
|
</a-col>
|
||||||
|
</a-row>
|
||||||
|
</template>
|
||||||
|
</a-list>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="favs/authors" tab="Authors">
|
||||||
|
<a-list
|
||||||
|
item-layout="horizontal"
|
||||||
|
:data-source="userInfo?.favs.authors"
|
||||||
|
:grid="{ gutter: 16, column: 3 }"
|
||||||
|
>
|
||||||
|
<template #renderItem="{ item }">
|
||||||
|
<a-list-item style="display: flex; align-items: center">
|
||||||
|
<a-list-item-meta
|
||||||
|
style="align-items: center; width: min-content"
|
||||||
|
>
|
||||||
|
<template #avatar>
|
||||||
|
<a-avatar :src="`/avatars/${item.profile.avatar}.png`" />
|
||||||
|
</template>
|
||||||
|
<template #title :style="{ background: 'pink' }">
|
||||||
|
<nuxt-link :to="`/user/${item._id}`">
|
||||||
|
{{ item.username }}
|
||||||
|
</nuxt-link>
|
||||||
|
</template>
|
||||||
|
</a-list-item-meta>
|
||||||
|
<template #actions v-if="isSelf">
|
||||||
|
<span>
|
||||||
|
<a
|
||||||
|
style="color: red"
|
||||||
|
@click="
|
||||||
|
() =>
|
||||||
|
favourites(
|
||||||
|
userInfo?.favs.authors || [],
|
||||||
|
item._id,
|
||||||
|
true,
|
||||||
|
'author',
|
||||||
|
)
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<icon istyle="regular" name="trash" color="#f00" />
|
||||||
|
</a>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
|
</a-list-item>
|
||||||
|
</template>
|
||||||
|
</a-list>
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
</a-tab-pane>
|
||||||
|
<a-tab-pane key="admin" tab="Admin" v-if="data?.user?.profile.isAdmin">
|
||||||
|
<admin-panel :user="userInfo" />
|
||||||
|
</a-tab-pane>
|
||||||
|
</a-tabs>
|
||||||
|
</a-card>
|
||||||
|
</template>
|
||||||
|
<style>
|
||||||
|
.ant-list-item-action {
|
||||||
|
width: min-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-ribbon-wrapper {
|
||||||
|
position: unset !important;
|
||||||
|
zoom: 200%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-list-item-meta-title {
|
||||||
|
margin-top: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-card-head-title,
|
||||||
|
.ant-card-head {
|
||||||
|
height: 110% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-list-item-meta-content {
|
||||||
|
align-self: center !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<style scoped>
|
||||||
|
.ant-list-items > * + * {
|
||||||
|
margin-top: 1.2em;
|
||||||
|
}
|
||||||
|
</style>
|
Loading…
Reference in New Issue
Block a user