Skip to content

Commit 6d6612b

Browse files
zackhaSaganicj0rgedev
committed
feat: added user api' s
Co-Authored-By: Chris Saganic <chris@saganic.co.uk> Co-Authored-By: Jorge A. <102924003+j0rgedev@users.noreply.github.com>
1 parent d3bc9f8 commit 6d6612b

File tree

9 files changed

+111
-45
lines changed

9 files changed

+111
-45
lines changed

app/components/Dropdown.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="ts">
2-
const { clear, user } = useUserSession();
2+
const { clear } = useUserSession();
33
const colorMode = useColorMode();
44
55
const isDarkMode = computed({

app/components/ProfileActions.vue

-18
This file was deleted.

app/components/ProfileHeader.vue

+32-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,36 @@
1+
<script setup lang="ts">
2+
const { loggedIn, session } = useUserSession();
3+
const createHabitModal = ref(false);
4+
defineProps<{ user: User }>();
5+
const isOwnProfile = computed(() => session.value.user?.login === useRoute().params.user);
6+
</script>
7+
18
<template>
29
<div class="relative flex p-5">
3-
<UserProfileInfo />
4-
<ProfileActions />
10+
<div class="flex flex-col gap-3">
11+
<UAvatar size="3xl" :src="user?.avatarUrl" :alt="user?.login" />
12+
<div class="flex flex-col gap-1">
13+
<div class="text-xl font-medium">{{ user?.name }}</div>
14+
<div class="text-xs text-white/40">{{ user?.bio }}</div>
15+
</div>
16+
</div>
17+
<div v-if="isOwnProfile" class="absolute right-5 top-5 flex gap-3">
18+
<button class="button bg-white/20 py-1.5 pl-2 pr-2.5 hover:bg-white/25" @click="createHabitModal = true">
19+
<UIcon name="i-heroicons-plus-16-solid" class="h-5 w-5" />
20+
Create
21+
</button>
22+
<Dropdown />
23+
</div>
24+
<div v-else-if="!loggedIn" class="absolute right-5 top-5 flex gap-3">
25+
<a href="/api/auth/github" class="button bg-white/20 px-2 py-1.5 hover:bg-white/25">
26+
<UIcon name="i-simple-icons-github" class="h-5 w-5" />
27+
Sign in
28+
</a>
29+
</div>
30+
<UModal
31+
v-model="createHabitModal"
32+
:ui="{ container: 'items-center', width: 'w-96', background: '', shadow: '', overlay: { base: 'backdrop-blur-2xl', background: 'bg-white/5 dark:bg-black/60' } }">
33+
<HabitForm @habitAdded="createHabitModal = false" />
34+
</UModal>
535
</div>
636
</template>

app/components/UserProfileInfo.vue

-13
This file was deleted.

app/pages/[user].vue

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,38 @@
11
<script setup lang="ts">
22
const router = useRoute();
33
4+
const { data: user } = useQuery({
5+
key: ['user'],
6+
query: () => useRequestFetch()(`/api/users/${router.params.user}`) as Promise<User>,
7+
});
8+
49
const { data: habits } = useQuery({
510
key: ['habits'],
6-
query: () => useRequestFetch()('/api/habits') as Promise<Habit[]>,
11+
query: () => useRequestFetch()(`/api/users/${router.params.user}/habits`) as Promise<Habit[]>,
712
});
813
914
const emptyHabits = computed(() => habits.value?.length === 0);
1015
</script>
1116

1217
<template>
13-
<Card>
18+
<Card v-if="user">
1419
<div class="relative z-10">
15-
<ProfileHeader />
20+
<ProfileHeader :user="user" />
1621
<div class="scrollable-card max-h-[calc(100vh-18.875rem)] overflow-y-auto">
1722
<HabitCard v-for="habit in habits" :key="habit.id" :habit="habit" />
1823
</div>
1924
<EmptyHabits v-if="emptyHabits" />
2025
</div>
2126
</Card>
27+
<Card v-else class="items-start justify-center gap-7 p-6">
28+
<div class="relative z-10 flex w-5/6 flex-col gap-5">
29+
<div class="text-3xl font-semibold">404</div>
30+
<p class="font-semibold">Sorry, this page isn't available.</p>
31+
<p class="text-sm text-white/50">The link you followed may be broken, or the page may have been removed.</p>
32+
</div>
33+
<a href="/" class="button bg-white/20 px-2.5 py-2 hover:bg-white/30">
34+
<UIcon name="i-heroicons-arrow-left-16-solid" class="h-5 w-5" />
35+
Go back to Habit
36+
</a>
37+
</Card>
2238
</template>

pnpm-lock.yaml

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { eq } from 'drizzle-orm';
2+
import { useValidatedParams, z } from 'h3-zod';
3+
4+
export default eventHandler(async event => {
5+
const { login } = await useValidatedParams(event, {
6+
login: z.string().toLowerCase(),
7+
});
8+
9+
const user = await useDB()
10+
.select()
11+
.from(tables.users)
12+
.where(and(eq(tables.users.login, login), eq(tables.users.userView, true)))
13+
.get();
14+
15+
if (!user) {
16+
return [] as Habit[];
17+
}
18+
19+
const habits = await useDB()
20+
.select()
21+
.from(tables.habits)
22+
.where(and(eq(tables.habits.userId, user.id), eq(tables.habits.habitView, true)))
23+
.all();
24+
25+
return habits as Habit[];
26+
});

server/api/users/[login]/index.get.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { eq } from 'drizzle-orm';
2+
import { useValidatedParams, z } from 'h3-zod';
3+
4+
export default eventHandler(async event => {
5+
const { login } = await useValidatedParams(event, {
6+
login: z.string().toLowerCase(),
7+
});
8+
9+
const user = await useDB()
10+
.select()
11+
.from(tables.users)
12+
.where(and(eq(tables.users.login, login), eq(tables.users.userView, true)))
13+
.get();
14+
15+
return user as User;
16+
});

server/api/users/index.get.ts

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { eq } from 'drizzle-orm';
2+
3+
export default eventHandler(async event => {
4+
const { user: requestUser } = await requireUserSession(event);
5+
6+
const user = await useDB().select().from(tables.users).where(eq(tables.habits.userId, requestUser.id)).limit(1).get();
7+
8+
return user;
9+
});

0 commit comments

Comments
 (0)