Skip to content

Commit

Permalink
feat: web: profile (#218)
Browse files Browse the repository at this point in the history
  • Loading branch information
crlssn authored Dec 13, 2024
1 parent 587248b commit 94efd31
Show file tree
Hide file tree
Showing 12 changed files with 101 additions and 39 deletions.
3 changes: 2 additions & 1 deletion proto/api/v1/shared.proto
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ message User {
string id = 1 [(buf.validate.field).string.uuid = true];
string first_name = 2 [(buf.validate.field).string.min_len = 1];
string last_name = 3 [(buf.validate.field).string.min_len = 1];
bool followed = 4;
string email = 4;
bool followed = 5;
}

message PaginationRequest {
Expand Down
57 changes: 33 additions & 24 deletions server/pkg/proto/api/v1/shared.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions server/pkg/repo/repo.go
Original file line number Diff line number Diff line change
Expand Up @@ -1165,6 +1165,12 @@ func (r *Repo) IsUserFollowedByUserID(ctx context.Context, user *orm.User, userI

type GetAuthOpt func() qm.QueryMod

func GetAuthByID(id string) GetAuthOpt {
return func() qm.QueryMod {
return orm.AuthWhere.ID.EQ(id)
}
}

func GetAuthByEmail(email string) GetAuthOpt {
return func() qm.QueryMod {
return orm.AuthWhere.Email.EQ(email)
Expand Down
12 changes: 11 additions & 1 deletion server/rpc/v1/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,25 @@ func (h *userHandler) GetUser(ctx context.Context, req *connect.Request[v1.GetUs
return nil, connect.NewError(connect.CodeInternal, nil)
}

auth, err := h.repo.GetAuth(ctx, repo.GetAuthByID(user.ID))
if err != nil {
log.Error("failed to get auth", zap.Error(err))
return nil, connect.NewError(connect.CodeInternal, nil)
}

followed, err := h.repo.IsUserFollowedByUserID(ctx, user, userID)
if err != nil {
log.Error("failed to check if user is followed", zap.Error(err))
return nil, connect.NewError(connect.CodeInternal, nil)
}

// DEBT: Move email to user model.
u := parseUserToPB(user, followed)
u.Email = auth.Email

return &connect.Response[v1.GetUserResponse]{
Msg: &v1.GetUserResponse{
User: parseUserToPB(user, followed),
User: u,
},
}, nil
}
Expand Down
9 changes: 7 additions & 2 deletions web/src/proto/api/v1/shared_pb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type { Message } from "@bufbuild/protobuf";
* Describes the file api/v1/shared.proto.
*/
export const file_api_v1_shared: GenFile = /*@__PURE__*/
fileDesc("ChNhcGkvdjEvc2hhcmVkLnByb3RvEgZhcGkudjEiXwoMRXhlcmNpc2VTZXRzEioKCGV4ZXJjaXNlGAEgASgLMhAuYXBpLnYxLkV4ZXJjaXNlQga6SAPIAQESIwoEc2V0cxgCIAMoCzILLmFwaS52MS5TZXRCCLpIBZIBAggBIk4KCEV4ZXJjaXNlEhQKAmlkGAEgASgJQgi6SAVyA7ABARIPCgd1c2VyX2lkGAIgASgJEgwKBG5hbWUYAyABKAkSDQoFbGFiZWwYBCABKAkiUwoDU2V0Eg4KBndlaWdodBgBIAEoARIVCgRyZXBzGAIgASgFQge6SAQaAigBEiUKCG1ldGFkYXRhGAMgASgLMhMuYXBpLnYxLk1ldGFkYXRhU2V0IlsKC01ldGFkYXRhU2V0EhwKCndvcmtvdXRfaWQYASABKAlCCLpIBXIDsAEBEi4KCmNyZWF0ZWRfYXQYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wImcKBFVzZXISFAoCaWQYASABKAlCCLpIBXIDsAEBEhsKCmZpcnN0X25hbWUYAiABKAlCB7pIBHICEAESGgoJbGFzdF9uYW1lGAMgASgJQge6SARyAhABEhAKCGZvbGxvd2VkGAQgASgIIkYKEVBhZ2luYXRpb25SZXF1ZXN0Eh0KCnBhZ2VfbGltaXQYASABKAVCCbpIBhoEGGQoARISCgpwYWdlX3Rva2VuGAIgASgMIi0KElBhZ2luYXRpb25SZXNwb25zZRIXCg9uZXh0X3BhZ2VfdG9rZW4YASABKAxCjwEKCmNvbS5hcGkudjFCC1NoYXJlZFByb3RvUAFaO2dpdGh1Yi5jb20vY3Jsc3NuL2dldHN0cm9uZ2VyL3NlcnZlci9wa2cvcHJvdG8vYXBpL3YxO2FwaXYxogIDQVhYqgIGQXBpLlYxygIGQXBpXFYx4gISQXBpXFYxXEdQQk1ldGFkYXRh6gIHQXBpOjpWMWIGcHJvdG8z", [file_buf_validate_validate, file_google_protobuf_timestamp]);
fileDesc("ChNhcGkvdjEvc2hhcmVkLnByb3RvEgZhcGkudjEiXwoMRXhlcmNpc2VTZXRzEioKCGV4ZXJjaXNlGAEgASgLMhAuYXBpLnYxLkV4ZXJjaXNlQga6SAPIAQESIwoEc2V0cxgCIAMoCzILLmFwaS52MS5TZXRCCLpIBZIBAggBIk4KCEV4ZXJjaXNlEhQKAmlkGAEgASgJQgi6SAVyA7ABARIPCgd1c2VyX2lkGAIgASgJEgwKBG5hbWUYAyABKAkSDQoFbGFiZWwYBCABKAkiUwoDU2V0Eg4KBndlaWdodBgBIAEoARIVCgRyZXBzGAIgASgFQge6SAQaAigBEiUKCG1ldGFkYXRhGAMgASgLMhMuYXBpLnYxLk1ldGFkYXRhU2V0IlsKC01ldGFkYXRhU2V0EhwKCndvcmtvdXRfaWQYASABKAlCCLpIBXIDsAEBEi4KCmNyZWF0ZWRfYXQYAiABKAsyGi5nb29nbGUucHJvdG9idWYuVGltZXN0YW1wInYKBFVzZXISFAoCaWQYASABKAlCCLpIBXIDsAEBEhsKCmZpcnN0X25hbWUYAiABKAlCB7pIBHICEAESGgoJbGFzdF9uYW1lGAMgASgJQge6SARyAhABEg0KBWVtYWlsGAQgASgJEhAKCGZvbGxvd2VkGAUgASgIIkYKEVBhZ2luYXRpb25SZXF1ZXN0Eh0KCnBhZ2VfbGltaXQYASABKAVCCbpIBhoEGGQoARISCgpwYWdlX3Rva2VuGAIgASgMIi0KElBhZ2luYXRpb25SZXNwb25zZRIXCg9uZXh0X3BhZ2VfdG9rZW4YASABKAxCjwEKCmNvbS5hcGkudjFCC1NoYXJlZFByb3RvUAFaO2dpdGh1Yi5jb20vY3Jsc3NuL2dldHN0cm9uZ2VyL3NlcnZlci9wa2cvcHJvdG8vYXBpL3YxO2FwaXYxogIDQVhYqgIGQXBpLlYxygIGQXBpXFYx4gISQXBpXFYxXEdQQk1ldGFkYXRh6gIHQXBpOjpWMWIGcHJvdG8z", [file_buf_validate_validate, file_google_protobuf_timestamp]);

/**
* @generated from message api.v1.ExerciseSets
Expand Down Expand Up @@ -140,7 +140,12 @@ export type User = Message<"api.v1.User"> & {
lastName: string;

/**
* @generated from field: bool followed = 4;
* @generated from field: string email = 4;
*/
email: string;

/**
* @generated from field: bool followed = 5;
*/
followed: boolean;
};
Expand Down
10 changes: 5 additions & 5 deletions web/src/stores/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,21 @@ import { jwtDecode } from 'jwt-decode'
export const useAuthStore = defineStore(
'auth',
() => {
const userID = ref('')
const userId = ref('')
const accessToken = ref('')
const accessTokenRefreshInterval = ref(0)

const setAccessToken = (token: string) => {
console.log('setting access token', token)
if (userID.value === '') {
if (userId.value === '') {
const claims = jwtDecode(token) as AccessToken
userID.value = claims.userId
userId.value = claims.userId
}
accessToken.value = token
}

const logout = () => {
userID.value = ''
userId.value = ''
accessToken.value = ''
clearInterval(accessTokenRefreshInterval.value)
}
Expand All @@ -30,7 +30,7 @@ export const useAuthStore = defineStore(
accessTokenRefreshInterval.value = interval
}

return { accessToken, logout, setAccessToken, setAccessTokenRefreshInterval, userID }
return { accessToken, logout, setAccessToken, setAccessTokenRefreshInterval, userId }
},
{
persist: true,
Expand Down
2 changes: 1 addition & 1 deletion web/src/ui/components/CardWorkout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const formatComment = computed(() => {
{{ formatToRelativeDateTime(props.workout.finishedAt) }}
</RouterLink>
</div>
<DropdownButton v-if="workout.user?.id === authStore.userID" :items="dropdownItems" />
<DropdownButton v-if="workout.user?.id === authStore.userId" :items="dropdownItems" />
</div>
</div>
<div class="pl-16 pr-4 py-4">
Expand Down
2 changes: 1 addition & 1 deletion web/src/ui/components/NotificationWorkoutComment.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const props = defineProps<{
}>()
const workoutOwnership = computed(() => {
if (authStore.userID === props.workout?.user?.id) {
if (authStore.userId === props.workout?.user?.id) {
return 'your'
}
Expand Down
2 changes: 1 addition & 1 deletion web/src/ui/exercises/ViewExercise.vue
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ const onDeleteExercise = async () => {
</AppListItemLink>
</AppList>

<div v-if="authStore.userID === exercise?.userId">
<div v-if="authStore.userId === exercise?.userId">
<h6 class="mt-8">Admin</h6>
<AppList>
<AppListItemLink :to="`/exercises/${route.params.id}/edit`">
Expand Down
33 changes: 32 additions & 1 deletion web/src/ui/profile/ProfileView.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,40 @@
<script setup lang="ts">
import AppButton from '@/ui/components/AppButton.vue'
import { onMounted, ref } from 'vue'
import { getUser } from '@/http/requests.ts'
import { useAuthStore } from '@/stores/auth.ts'
import type { User } from '@/proto/api/v1/shared_pb.ts'
import { UserCircleIcon } from '@heroicons/vue/24/solid'
const user = ref<User>()
onMounted(async () => {
await fetchUser()
})
const fetchUser = async () => {
const res = await getUser(useAuthStore().userId)
if (!res) return
user.value = res.user
}
</script>

<template>
<div class="container">
<UserCircleIcon class="size-48 mx-auto text-gray-900" />
<h1>{{ user?.firstName }} {{ user?.lastName }}</h1>
<p>{{ user?.email }}</p>
</div>
<AppButton type="link" to="/logout" colour="red" container-class="px-4 pb-4"> Logout </AppButton>
</template>

<style scoped></style>
<style scoped>
.container {
@apply text-center mb-4;
}
h1 {
@apply text-xl font-medium;
}
</style>
2 changes: 1 addition & 1 deletion web/src/ui/users/UserView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ const updateTab = (event: Event) => {
</script>

<template>
<div v-if="user.id !== authStore.userID">
<div v-if="user.id !== authStore.userId">
<AppButton
v-if="user.followed"
colour="gray"
Expand Down
2 changes: 1 addition & 1 deletion web/src/ui/workouts/EditWorkout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const fetchWorkout = async (id: string) => {
const res = await getWorkout(id)
if (!res) return
if (res.workout?.user?.id !== authStore.userID) {
if (res.workout?.user?.id !== authStore.userId) {
alertStore.setError('You do not have permission to edit this workout')
await router.push('/home')
return
Expand Down

0 comments on commit 94efd31

Please sign in to comment.