-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #22 from fiit-tp7-2023/AB#350-user-profile-page
Ab#350 user profile page
- Loading branch information
Showing
11 changed files
with
448 additions
and
11 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,142 @@ | ||
<template> | ||
<div> | ||
<h1>User profile</h1> | ||
<h2>{{ address }}</h2> | ||
<div class="profile-container"> | ||
<h1 class="text-2xl font-mono text-pink-500">{{ userProfile.username }}</h1> | ||
<div class="user-details mt-4 bg-slate-900 text-white p-6 rounded-lg flex"> | ||
<img | ||
:src="userProfile.profilePicture || 'default-profile.png'" | ||
alt="Profile Picture" | ||
class="profile-picture shadow-lg" | ||
/> | ||
<div class="info ml-6"> | ||
<h2 class="text-xl font-mono">{{ userProfile.address }}</h2> | ||
<div class="follow-info mt-4"> | ||
<h3>Followers: {{ userProfile.followerCount }}</h3> | ||
<h3>Following: {{ userProfile.followingCount }}</h3> | ||
</div> | ||
<button v-if="!userProfile.isOwnProfile" class="follow-button" @click="followUser">Follow</button> | ||
</div> | ||
</div> | ||
<hr class="mt-6 border-t border-gray-500" /> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts" setup> | ||
import { computed } from 'vue'; | ||
import { ref, onMounted } from 'vue'; | ||
import { useRoute } from 'vue-router'; | ||
import { useAccountStore } from '~/store'; | ||
const error = ref<Error | null>(null); | ||
const route = useRoute(); | ||
const address = computed(() => route.params.address); | ||
const accountStore = useAccountStore(); | ||
const userProfile = ref({ | ||
username: '', | ||
address: '', | ||
profilePicture: '', | ||
followerCount: 0, | ||
followingCount: 0, | ||
isOwnProfile: false, | ||
}); | ||
const fetchUserProfile = async () => { | ||
const address = route.params.address; // Get the address from the URL parameter | ||
try { | ||
const data = await $fetch(`/api/user/${address}`, { | ||
headers: { | ||
Authorization: `Bearer ${accountStore.accessToken}`, | ||
}, | ||
}); | ||
userProfile.value = { | ||
...data, | ||
username: data.username || 'Anonymous', // Default if undefined | ||
profilePicture: data.profilePicture || 'default-profile.png', | ||
isOwnProfile: accountStore.address === address, | ||
followerCount: data.followerCount || 0, // Default to 0 if undefined | ||
followingCount: data.followingCount || 0, | ||
}; | ||
} catch (e) { | ||
error.value = e as Error; | ||
} | ||
}; | ||
const followUser = async () => { | ||
await $fetch(`/api/user/:id/following`, { | ||
method: 'POST', | ||
headers: { | ||
Authorization: `Bearer ${accountStore.accessToken}`, | ||
}, | ||
}); | ||
fetchUserProfile(); // Re-fetch or adjust local state to show updated follower count | ||
}; | ||
onMounted(fetchUserProfile); | ||
</script> | ||
|
||
<style></style> | ||
<style scoped> | ||
.profile-container { | ||
@apply max-w-5xl mx-auto p-5 shadow-lg rounded-lg bg-[#1e293b]; | ||
} | ||
.user-details { | ||
@apply flex items-center justify-between bg-[#1e293b] rounded-lg p-5; | ||
} | ||
.profile-picture { | ||
@apply w-36 h-36 rounded-full object-cover border-4 border-white shadow-lg; | ||
} | ||
.info { | ||
@apply flex flex-col justify-center ml-5 grow; | ||
} | ||
h1, | ||
h2, | ||
h3 { | ||
@apply text-white; | ||
} | ||
h1 { | ||
@apply text-2xl font-mono text-[#f472b6]; | ||
} | ||
h2 { | ||
@apply text-xl font-mono; | ||
} | ||
.follow-button { | ||
@apply mt-5 py-2.5 px-5 bg-[#f472b6] text-white border-none rounded cursor-pointer transition-colors; | ||
width: 100%; /* Ensures the button stretches to fill its container */ | ||
} | ||
.follow-button:hover { | ||
@apply bg-[#ec4899]; | ||
} | ||
.follow-info { | ||
@apply flex gap-5 mt-2.5 justify-end items-center; | ||
width: 100%; /* This ensures the flex container takes full width */ | ||
} | ||
.follow-info h3 { | ||
@apply bg-[rgba(255,255,255,0.1)] py-2.5 px-2.5 rounded flex-1 text-center; /* flex-1 allows each item to take equal space */ | ||
} | ||
hr { | ||
@apply mt-5 border-t border-[rgba(130,130,130,0.5)]; | ||
} | ||
@media (max-width: 768px) { | ||
.user-details { | ||
@apply flex-col items-center; | ||
} | ||
.info { | ||
@apply ml-0 mt-5; | ||
} | ||
.follow-info { | ||
@apply justify-center; | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,118 @@ | ||
<template> | ||
<div>Your profile</div> | ||
<div class="profile-container"> | ||
<h1 class="text-2xl font-mono text-pink-500">{{ userProfile.username }}</h1> | ||
<div class="user-details mt-4 bg-slate-900 text-white p-6 rounded-lg flex"> | ||
<img :src="userProfile.profilePicture" alt="Profile Picture" class="profile-picture shadow-lg" /> | ||
<div class="info ml-6"> | ||
<h2 class="text-xl font-mono">{{ userProfile.address }}</h2> | ||
<div class="follow-info mt-4"> | ||
<h3>Followers: {{ userProfile.followerCount }}</h3> | ||
<h3>Following: {{ userProfile.followingCount }}</h3> | ||
</div> | ||
</div> | ||
</div> | ||
<hr class="mt-6 border-t border-gray-500" /> | ||
</div> | ||
</template> | ||
|
||
<script lang="ts" setup></script> | ||
<script lang="ts" setup> | ||
import { useAccountStore } from '~/store'; | ||
<style></style> | ||
const accountStore = useAccountStore(); | ||
const error = ref<Error | null>(null); | ||
const userProfile = ref({ | ||
username: '', | ||
address: '', | ||
profilePicture: '', | ||
followerCount: 0, | ||
followingCount: 0, | ||
isOwnProfile: false, | ||
}); | ||
const fetchUserProfile = async () => { | ||
try { | ||
const data = await $fetch(`/api/user/${accountStore.address}`, { | ||
headers: { | ||
Authorization: `Bearer ${accountStore.accessToken}`, | ||
}, | ||
}); | ||
userProfile.value = { | ||
...data, | ||
username: data.username || 'Anonymous', | ||
profilePicture: data.profilePicture || '', | ||
isOwnProfile: true, | ||
followerCount: data.followerCount || 0, | ||
followingCount: data.followingCount || 0, | ||
}; | ||
} catch (e) { | ||
error.value = e as Error; | ||
} | ||
}; | ||
onMounted(fetchUserProfile); | ||
</script> | ||
|
||
<style scoped> | ||
.profile-container { | ||
@apply max-w-5xl mx-auto p-5 shadow-lg rounded-lg bg-[#1e293b]; | ||
} | ||
.user-details { | ||
@apply flex items-center bg-[#1e293b] rounded-lg p-5; | ||
} | ||
.profile-picture { | ||
@apply w-36 h-36 rounded-full object-cover border-4 border-white shadow-lg; | ||
} | ||
.info { | ||
@apply flex flex-col justify-center ml-5; | ||
} | ||
h1, | ||
h2, | ||
h3 { | ||
@apply text-white; | ||
} | ||
h1 { | ||
@apply text-2xl font-mono text-[#f472b6]; | ||
} | ||
h2 { | ||
@apply text-xl font-mono; | ||
} | ||
.follow-button { | ||
@apply mt-5 py-2.5 px-5 bg-[#f472b6] text-white border-none rounded cursor-pointer transition-colors; | ||
} | ||
.follow-button:hover { | ||
@apply bg-[#ec4899]; | ||
} | ||
.follow-info { | ||
@apply flex gap-5 mt-2.5 justify-end; | ||
} | ||
.follow-info h3 { | ||
@apply bg-[rgba(255,255,255,0.1)] py-2.5 px-2.5 rounded; | ||
} | ||
hr { | ||
@apply mt-5 border-t border-[rgba(130,130,130,0.5)]; | ||
} | ||
@media (max-width: 768px) { | ||
.user-details { | ||
@apply flex-col items-center; | ||
} | ||
.info { | ||
@apply ml-0 mt-5; | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { useUserService } from '~/server/services/user.service'; | ||
|
||
export default defineEventHandler(async (event) => { | ||
const jwt = getHeader(event, 'Authorization')?.split('Bearer ')[1]; | ||
const nftAddress = getRouterParam(event, 'id'); | ||
if (!jwt) { | ||
throw createError({ | ||
message: 'Unauthorized', | ||
}); | ||
} | ||
if (!nftAddress) { | ||
throw createError({ | ||
message: 'Invalid NFT address', | ||
}); | ||
} | ||
const service = useUserService(jwt); | ||
return await service.deleteFollowers(nftAddress); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { useUserService } from '~/server/services/user.service'; | ||
|
||
export default defineEventHandler(async (event) => { | ||
const jwt = getHeader(event, 'Authorization')?.split('Bearer ')[1]; | ||
const nftAddress = getRouterParam(event, 'id'); | ||
if (!jwt) { | ||
throw createError({ | ||
message: 'Unauthorized', | ||
}); | ||
} | ||
if (!nftAddress) { | ||
throw createError({ | ||
message: 'Invalid NFT address', | ||
}); | ||
} | ||
const service = useUserService(jwt); | ||
return await service.getFollowers(nftAddress); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { useUserService } from '~/server/services/user.service'; | ||
|
||
export default defineEventHandler(async (event) => { | ||
const jwt = getHeader(event, 'Authorization')?.split('Bearer ')[1]; | ||
const nftAddress = getRouterParam(event, 'id'); | ||
if (!jwt) { | ||
throw createError({ | ||
message: 'Unauthorized', | ||
}); | ||
} | ||
if (!nftAddress) { | ||
throw createError({ | ||
message: 'Invalid NFT address', | ||
}); | ||
} | ||
const service = useUserService(jwt); | ||
return await service.deleteFollow(nftAddress); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { useUserService } from '~/server/services/user.service'; | ||
|
||
export default defineEventHandler(async (event) => { | ||
const jwt = getHeader(event, 'Authorization')?.split('Bearer ')[1]; | ||
const nftAddress = getRouterParam(event, 'id'); | ||
if (!jwt) { | ||
throw createError({ | ||
message: 'Unauthorized', | ||
}); | ||
} | ||
if (!nftAddress) { | ||
throw createError({ | ||
message: 'Invalid NFT address', | ||
}); | ||
} | ||
const service = useUserService(jwt); | ||
return await service.getFollowing(nftAddress); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { useUserService } from '~/server/services/user.service'; | ||
|
||
export default defineEventHandler(async (event) => { | ||
const jwt = getHeader(event, 'Authorization')?.split('Bearer ')[1]; | ||
const nftAddress = getRouterParam(event, 'id'); | ||
if (!jwt) { | ||
throw createError({ | ||
message: 'Unauthorized', | ||
}); | ||
} | ||
if (!nftAddress) { | ||
throw createError({ | ||
message: 'Invalid NFT address', | ||
}); | ||
} | ||
const service = useUserService(jwt); | ||
return await service.follow(nftAddress); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { useUserService } from '~/server/services/user.service'; | ||
|
||
export default defineEventHandler(async (event) => { | ||
const jwt = getHeader(event, 'Authorization')?.split('Bearer ')[1]; | ||
const nftAddress = getRouterParam(event, 'id'); | ||
if (!jwt) { | ||
throw createError({ | ||
message: 'Unauthorized', | ||
}); | ||
} | ||
if (!nftAddress) { | ||
throw createError({ | ||
message: 'Invalid NFT address', | ||
}); | ||
} | ||
const service = useUserService(jwt); | ||
return await service.getUserProfile(nftAddress); | ||
}); |
Oops, something went wrong.