-
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 #16 from BeatBuzzer/feat/home-view
Feat/home view
- Loading branch information
Showing
23 changed files
with
923 additions
and
542 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
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,104 @@ | ||
<script setup lang="ts"> | ||
import type {GetFriendsResponse} from "@/types/api/user.friends"; | ||
import {UserViewType} from "@/types/components/users.view"; | ||
import type {GetUserResponse} from "@/types/api/users"; | ||
// Props | ||
const props = defineProps({ | ||
viewType: { | ||
type: Number, | ||
required: true, | ||
}, | ||
users: { | ||
type: Array as PropType<GetFriendsResponse[] | GetUserResponse[]>, | ||
required: true, | ||
} | ||
}); | ||
const default_avatar = ref('https://t4.ftcdn.net/jpg/05/49/98/39/360_F_549983970_bRCkYfk0P6PP5fKbMhZMIb07mCJ6esXL.jpg'); | ||
// Computed Classes | ||
const containerClasses = computed(() => { | ||
const baseClasses = 'w-full bg-gray-200 px-3 pb-1 mt-auto rounded-3xl mb-3'; | ||
if (props.viewType === UserViewType.USERTURN) return `${baseClasses} h-full overflow-y-hidden overflow-x-auto flex-grow-0`; | ||
if (props.viewType === UserViewType.OPPONENTTURN || props.viewType === UserViewType.FRIENDS) return `${baseClasses} overflow-y-hidden`; | ||
return ''; | ||
}); | ||
const userBoxContainerClasses = computed(() => | ||
props.viewType === UserViewType.USERTURN | ||
? 'flex flex-col space-y-1 md:space-y-3 h-full overflow-y-auto' | ||
: 'flex gap-1 md:gap-3 mt-6 md:mt-9' | ||
); | ||
function isGetFriendsResponse(user: GetFriendsResponse | GetUserResponse): user is GetFriendsResponse { | ||
return 'friend_id' in user; | ||
} | ||
function isUserInformation(user: GetFriendsResponse | GetUserResponse): user is GetUserResponse { | ||
return 'id' in user && 'username' in user; | ||
} | ||
// Map users conditionally depending on their type | ||
const mappedUsers: Array<GetUserResponse> = computed(() => { | ||
return props.users.map(user => { | ||
if (isGetFriendsResponse(user)) { | ||
return user.user; | ||
} else if (isUserInformation(user)) { | ||
return user; | ||
} | ||
return {}; | ||
}); | ||
}); | ||
</script> | ||
|
||
<template> | ||
<div | ||
:class="[ | ||
containerClasses, | ||
((viewType === UserViewType.FRIENDS || viewType === UserViewType.OPPONENTTURN) && users.length > 3) ? 'pr-0' : '' | ||
]" | ||
> | ||
<!-- Fixed Conditional Header --> | ||
<div class="mb-1 text-xs md:text-base bg-gray-200 mt-2"> | ||
<p v-if="viewType === UserViewType.USERTURN"> | ||
Your Turn | ||
</p> | ||
<p v-else-if="viewType === UserViewType.OPPONENTTURN" class="fixed"> | ||
Opponent's Turn | ||
</p> | ||
<p v-else-if="viewType === UserViewType.FRIENDS" class="fixed"> | ||
Friends | ||
</p> | ||
</div> | ||
|
||
<!-- Scrollable User Boxes --> | ||
<div | ||
v-if="users.length != 0" | ||
:class="userBoxContainerClasses" | ||
> | ||
<HomeUsersUserBox | ||
v-for="user in mappedUsers" | ||
:key="user.id" | ||
:profile-picture="user?.avatar_url ? user.avatar_url : default_avatar" | ||
:name="user.username" | ||
:user-turn="viewType === UserViewType.USERTURN" | ||
:class="[ | ||
(viewType === UserViewType.FRIENDS || viewType === UserViewType.OPPONENTTURN) | ||
? users.length === 3 ? 'w-1/3' | ||
: users.length === 2 ? 'w-1/2' | ||
: 'w-full' | ||
: '' | ||
]" | ||
:style="(viewType === UserViewType.FRIENDS || viewType === UserViewType.OPPONENTTURN) | ||
? users.length > 3 | ||
? { width: 'calc(33.33% - .98rem)', flexShrink: 0 } | ||
: {} | ||
: {}" | ||
/> | ||
<!-- Placeholder for scrolling --> | ||
<div v-if="users.length > 3" class="px-1 py-4"/> | ||
</div> | ||
</div> | ||
</template> |
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
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
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
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,41 +1,39 @@ | ||
<script setup lang="ts"> | ||
import { | ||
FriendshipStatus, | ||
FriendshipType, | ||
type GetFriendsResponse | ||
} from "@/types/api/user.friends"; | ||
import {FriendshipStatus, FriendshipType, type GetFriendsResponse} from "@/types/api/user.friends"; | ||
import { UserViewType } from "@/types/components/users.view"; | ||
const requests: Ref<GetFriendsResponse[]> = useState("incoming_friendships", () => []) | ||
const friends: Ref<GetFriendsResponse[]> = useState("accepted_friendships", () => []) | ||
const session = useSupabaseSession() | ||
onMounted(async () => { | ||
if (session.value) { | ||
await getFriendships() | ||
friends.value.push(friends.value[0]) | ||
} | ||
if (session.value) { | ||
await getFriendships() | ||
//friends.value.push(friends.value[0]) unexpected behavior on initial page load | ||
} | ||
}) | ||
async function getFriendships() { | ||
$fetch<GetFriendsResponse[]>('http://localhost:3000/api/v1/user/friends') | ||
.then((data) => { | ||
requests.value = data.filter((item) => item.request_type == FriendshipType.INCOMING && item.status === FriendshipStatus.PENDING) | ||
friends.value = data.filter((item) => item.status === FriendshipStatus.ACCEPTED) | ||
}); | ||
$fetch<GetFriendsResponse[]>('http://localhost:3000/api/v1/user/friends') | ||
.then((data) => { | ||
requests.value = data.filter((item) => item.request_type == FriendshipType.INCOMING && item.status === FriendshipStatus.PENDING) | ||
friends.value = data.filter((item) => item.status === FriendshipStatus.ACCEPTED) | ||
}); | ||
} | ||
function addFriend() { | ||
const newFriend = { | ||
friend_username: "sfsdf", | ||
} | ||
friends.value.push(newFriend) | ||
} | ||
</script> | ||
|
||
<template> | ||
<div class="w-full bg-gray-200 p-3 mt-auto rounded-3xl my-3"> | ||
<p class="my-1 ">Friends</p> | ||
<div class="flex space-x-3 overflow-x-auto"> | ||
<HomeUsersUserBox | ||
v-for="item in friends" :key="item.friend_id" :name="item.friend_id" :user-turn="false" | ||
class="shrink-0 w-[calc(33.33%-1rem)]" /> | ||
</div> | ||
|
||
<UsersView :view-type="UserViewType.FRIENDS" :users="friends"/> | ||
|
||
</div> | ||
</template> | ||
<div class="mt-3"> | ||
<button class="p-2 bg-blue-500 text-white rounded ml-2" @click="addFriend">Add Friend</button> | ||
</div> | ||
</template> |
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,21 +1,38 @@ | ||
<script setup lang="ts"> | ||
const session = useSupabaseSession() | ||
const {user, loading, error, fetchUser} = useUser() | ||
onMounted(async () => { | ||
if (session.value) { | ||
await fetchUser() | ||
} | ||
}) | ||
const default_avatar = ref('https://t4.ftcdn.net/jpg/05/49/98/39/360_F_549983970_bRCkYfk0P6PP5fKbMhZMIb07mCJ6esXL.jpg'); | ||
const formatDate = (dateString : string) => { | ||
const options = { year: "numeric", month: "short", day: "numeric" }; | ||
const formattedDate = new Intl.DateTimeFormat('en-US', options).format(new Date(dateString)); | ||
return formattedDate.replace(',', ''); | ||
}; | ||
</script> | ||
|
||
<template> | ||
<div> | ||
<div v-if="error" class="text-red-500">Error occurred: {{error}}</div> | ||
<div class="flex flex-col"> | ||
<div class="flex flex-col items-center justify-center mb-3"> | ||
<img | ||
src="https://i.scdn.co/image/ab6775700000ee855d4c281804e8773208248312" | ||
class="w-16 h-16 rounded-full" > | ||
<p>Nickname</p> | ||
</div> | ||
<div class="flex flex-col items-center justify-center mb-3"> | ||
<NuxtImg :src="loading || !user?.avatar_url ? default_avatar : user!.avatar_url" class="w-16 h-16 rounded-full"/> | ||
<p>{{ loading ? 'Loading.' : user?.username }}</p> | ||
</div> | ||
|
||
<div class="grid grid-cols-2 gap-4"> | ||
<div class="bg-gray-200 h-8 rounded-3xl px-3">Streak</div> | ||
<div class="bg-gray-200 h-8 rounded-3xl px-3">Games played</div> | ||
<div class="bg-gray-200 h-8 rounded-3xl px-3">Placeholder</div> | ||
<div class="bg-gray-200 h-8 rounded-3xl px-3">Date joined</div> | ||
</div> | ||
<div class="grid grid-cols-2 gap-4"> | ||
<div class="bg-gray-200 h-8 rounded-3xl px-3 flex items-center justify-center">Games played</div> | ||
<div class="bg-gray-200 h-8 rounded-3xl px-3 flex items-center justify-center">Streak: {{ user?.daily_streak }}</div> | ||
<div class="bg-gray-200 h-8 rounded-3xl px-3 flex items-center justify-center">Spotify: {{user?.spotify_visibility ? 'public' : 'private'}}</div> | ||
<div class="bg-gray-200 h-8 rounded-3xl px-3 flex items-center justify-center">Joined: {{ formatDate(session?.user.created_at) }}</div> | ||
</div> | ||
</div> | ||
</div> | ||
</template> |
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,34 @@ | ||
import type {GetUserResponse} from "@/types/api/users"; | ||
|
||
export const useUser = () => { | ||
const user = useState<GetUserResponse | null>('user', () => null) | ||
const loading = useState<boolean>('userLoading', () => false) | ||
const error = useState<string | null>('userError', () => null) | ||
|
||
const fetchUser = async () => { | ||
try { | ||
// Only set loading on initial fetch | ||
if (!user.value) { | ||
loading.value = true | ||
} | ||
|
||
user.value = await useProfileInformation() | ||
} catch (err) { | ||
error.value = 'Failed to fetch user' | ||
console.error(err) | ||
} finally { | ||
loading.value = false | ||
} | ||
} | ||
|
||
return { | ||
user, | ||
loading, | ||
error, | ||
fetchUser | ||
} | ||
} | ||
|
||
async function useProfileInformation() { | ||
return await $fetch<GetUserResponse>('http://localhost:3000/api/v1/user/') | ||
} |
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
Oops, something went wrong.