Skip to content

Commit

Permalink
feat: web: empty states (#229)
Browse files Browse the repository at this point in the history
  • Loading branch information
crlssn authored Dec 16, 2024
1 parent a1bb6ac commit a9982f0
Show file tree
Hide file tree
Showing 19 changed files with 257 additions and 259 deletions.
12 changes: 6 additions & 6 deletions server/rpc/v1/feed.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,18 @@ func (h *feedHandler) ListFeedItems(ctx context.Context, req *connect.Request[v1
}

if req.Msg.GetFollowedOnly() {
followers, err := h.repo.ListFollowers(ctx, userID)
followees, err := h.repo.ListFollowees(ctx, userID)
if err != nil {
log.Error("failed to list followers", zap.Error(err))
log.Error("failed to list followees", zap.Error(err))
return nil, connect.NewError(connect.CodeInternal, nil)
}

followerIDs := make([]string, 0, len(followers))
for _, follower := range followers {
followerIDs = append(followerIDs, follower.ID)
followeeIDs := make([]string, 0, len(followees))
for _, follower := range followees {
followeeIDs = append(followeeIDs, follower.ID)
}

opts = append(opts, repo.ListWorkoutsWithUserIDs(append(followerIDs, userID)...))
opts = append(opts, repo.ListWorkoutsWithUserIDs(append(followeeIDs, userID)...))
}

workouts, err := h.repo.ListWorkouts(ctx, opts...)
Expand Down
10 changes: 9 additions & 1 deletion web/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,13 @@ const authStore = useAuthStore()

<template>
<AppDashboard v-if="authStore.authorised()" />
<RouterView v-else />
<main v-else>
<RouterView />
</main>
</template>

<style scoped>
main {
@apply flex min-h-full flex-col justify-center px-4 max-w-4xl mx-auto;
}
</style>
5 changes: 5 additions & 0 deletions web/src/ui/HomeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import usePagination from '@/utils/usePagination'
import { vInfiniteScroll } from '@vueuse/components'
import { useNavTabs } from '@/stores/navTabs.ts'
import { useRoute } from 'vue-router'
import AppList from '@/ui/components/AppList.vue'
import AppListItem from '@/ui/components/AppListItem.vue'
const route = useRoute()
const navTabs = useNavTabs()
Expand Down Expand Up @@ -41,6 +43,9 @@ const fetchFeedItems = async () => {
</script>

<template>
<AppList v-if="feedItems.length === 0">
<AppListItem>Your workouts and the workouts of those you follow will appear here</AppListItem>
</AppList>
<template v-for="item in feedItems" :key="item.type.value?.id">
<CardWorkout v-if="item.type.case === 'workout'" compact :workout="item.type.value" />
</template>
Expand Down
66 changes: 30 additions & 36 deletions web/src/ui/auth/ForgotPassword.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { resetPassword } from '@/http/requests'
import AppButton from '@/ui/components/AppButton.vue'
import { RouterLink, useRoute, useRouter } from 'vue-router'
import { type ResetPasswordRequest } from '@/proto/api/v1/auth_service_pb'
import AppAlert from '@/ui/components/AppAlert.vue'
const route = useRoute()
const router = useRouter()
const req = ref<ResetPasswordRequest>({
Expand All @@ -23,46 +23,40 @@ const onSubmit = async () => {
</script>

<template>
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
<div
v-if="route.query.success === null"
class="bg-green-200 rounded-md py-3 px-5 mb-4 text-sm/6 text-green-800"
role="alert"
>
Please check your inbox to reset your password.
<AppAlert
v-if="useRoute().query.success === null"
type="success"
message="Please check your inbox to reset your password"
/>
<form class="space-y-6" method="POST" @submit.prevent="onSubmit">
<div>
<label for="email" class="block font-medium text-gray-900">Email address</label>
<div class="mt-2">
<input
id="email"
v-model="req.email"
name="email"
type="email"
autocomplete="email"
required
/>
</div>
<form class="space-y-6" method="POST" @submit.prevent="onSubmit">
<div>
<label for="email" class="block text-sm/6 font-medium text-gray-900">Email address</label>
<div class="mt-2">
<input
id="email"
v-model="req.email"
name="email"
type="email"
autocomplete="email"
required
/>
</div>
</div>
<div>
<AppButton type="submit" colour="primary"> Reset Password </AppButton>
</div>
</form>

<p class="mt-10 text-center text-sm/6 text-gray-400">
Remember your password?
<RouterLink to="/login" class="font-semibold text-indigo-600 hover:text-indigo-500">
Login
</RouterLink>
</p>
</div>
</div>
<div>
<AppButton type="submit" colour="primary"> Reset Password</AppButton>
</div>
</form>

<p class="mt-6 text-center text-gray-400">
Remember your password?
<RouterLink to="/login" class="font-semibold text-indigo-600 hover:text-indigo-500">
Login
</RouterLink>
</p>
</template>

<style scoped>
input {
@apply block w-full rounded-md border-0 bg-white py-3 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 text-sm;
@apply block w-full rounded-md border-0 bg-white py-3 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600;
}
</style>
76 changes: 35 additions & 41 deletions web/src/ui/auth/ResetPassword.vue
Original file line number Diff line number Diff line change
Expand Up @@ -23,53 +23,47 @@ const onSignup = async () => {
</script>

<template>
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
<div class="mt-10 sm:mx-auto sm:w-full sm:max-w-sm">
<form class="space-y-6" method="POST" @submit.prevent="onSignup">
<div>
<div class="flex items-center justify-between">
<label for="password" class="block text-sm/6 font-medium text-gray-900">Password</label>
</div>
<div class="mt-2">
<input
id="password"
v-model="req.password"
name="password"
type="password"
autocomplete="current-password"
required
/>
</div>
</div>
<form class="space-y-6" method="POST" @submit.prevent="onSignup">
<div>
<div class="flex items-center justify-between">
<label for="password" class="block font-medium text-gray-900">Password</label>
</div>
<div class="mt-2">
<input
id="password"
v-model="req.password"
name="password"
type="password"
autocomplete="current-password"
required
/>
</div>
</div>

<div>
<div class="flex items-center justify-between">
<label for="password" class="block text-sm/6 font-medium text-gray-900">
Confirm Password
</label>
</div>
<div class="mt-2">
<input
id="passwordConfirmation"
v-model="req.passwordConfirmation"
name="passwordConfirmation"
type="password"
autocomplete="current-password"
required
/>
</div>
</div>
<div>
<div class="flex items-center justify-between">
<label for="password" class="block font-medium text-gray-900"> Confirm Password </label>
</div>
<div class="mt-2">
<input
id="passwordConfirmation"
v-model="req.passwordConfirmation"
name="passwordConfirmation"
type="password"
autocomplete="current-password"
required
/>
</div>
</div>

<div>
<AppButton type="submit" colour="primary"> Update Password </AppButton>
</div>
</form>
<div>
<AppButton type="submit" colour="primary"> Update Password</AppButton>
</div>
</div>
</form>
</template>

<style scoped>
input {
@apply block w-full rounded-md border-0 bg-white py-3 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 text-sm;
@apply block w-full rounded-md border-0 bg-white py-3 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600;
}
</style>
126 changes: 55 additions & 71 deletions web/src/ui/auth/UserLogin.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { scheduleTokenRefresh } from '@/jwt/jwt'
import { RouterLink, useRoute } from 'vue-router'
import AppButton from '@/ui/components/AppButton.vue'
import { useNotificationStore } from '@/stores/notifications.ts'
import AppAlert from '@/ui/components/AppAlert.vue'
const email = ref('')
const password = ref('')
Expand All @@ -25,85 +26,68 @@ const onLogin = async () => {
</script>

<template>
<div class="flex min-h-full flex-col justify-center px-6 py-12 lg:px-8">
<div class="sm:mx-auto sm:w-full sm:max-w-sm">
<div
v-if="useRoute().query.success === null"
class="bg-green-200 rounded-md py-3 px-5 mb-4 text-sm/6 text-green-800"
role="alert"
>
Please check your inbox to verify your email before you login.
<AppAlert
v-if="useRoute().query.success === null"
type="success"
message="Please check your inbox to verify your email"
/>
<AppAlert
v-if="useRoute().query.verified === null"
type="success"
message="Thank you for verifying your email"
/>
<AppAlert
v-if="useRoute().query.reset === null"
type="success"
message="Your password has been reset"
/>
<form class="space-y-6" method="POST" @submit.prevent="onLogin">
<div>
<label for="email" class="block /6 font-medium text-gray-900">Email address</label>
<div class="mt-2">
<input id="email" v-model="email" name="email" type="email" autocomplete="email" required />
</div>
<div
v-if="useRoute().query.verified === null"
class="bg-green-200 rounded-md py-3 px-5 mb-4 text-sm/6 text-green-800"
role="alert"
>
Thank you for verifying your email. You can now login.
</div>
<div
v-if="useRoute().query.reset === null"
class="bg-green-200 rounded-md py-3 px-5 mb-4 text-sm/6 text-green-800"
role="alert"
>
Your password has been reset. You can now login.
</div>
<form class="space-y-6" method="POST" @submit.prevent="onLogin">
<div>
<label for="email" class="block text-sm/6 font-medium text-gray-900">Email address</label>
<div class="mt-2">
<input
id="email"
v-model="email"
name="email"
type="email"
autocomplete="email"
required
/>
</div>
</div>

<div>
<div class="flex items-center justify-between">
<label for="password" class="block text-sm/6 font-medium text-gray-900">Password</label>
<div class="text-sm">
<RouterLink
to="/forgot-password"
class="font-semibold text-indigo-600 hover:text-indigo-500"
>
Forgot password?
</RouterLink>
</div>
</div>
<div class="mt-2">
<input
id="password"
v-model="password"
name="password"
type="password"
autocomplete="current-password"
required
/>
</div>
</div>
</div>

<div>
<AppButton type="submit" colour="primary"> Login </AppButton>
<div>
<div class="flex items-center justify-between">
<label for="password" class="block font-medium text-gray-900">Password</label>
<div class="">
<RouterLink
to="/forgot-password"
class="font-semibold text-indigo-600 hover:text-indigo-500"
>
Forgot password?
</RouterLink>
</div>
</form>
</div>
<div class="mt-2">
<input
id="password"
v-model="password"
name="password"
type="password"
autocomplete="current-password"
required
/>
</div>
</div>

<p class="mt-10 text-center text-sm/6 text-gray-400">
Not a member?
<RouterLink to="signup" class="font-semibold text-indigo-600 hover:text-indigo-500">
Sign up
</RouterLink>
</p>
<div>
<AppButton type="submit" colour="primary"> Login</AppButton>
</div>
</div>
</form>

<p class="mt-6 text-center text-gray-400">
Not a member?
<RouterLink to="signup" class="font-semibold text-indigo-600 hover:text-indigo-500">
Sign up
</RouterLink>
</p>
</template>

<style scoped>
input {
@apply block w-full rounded-md border-0 bg-white py-3 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600 text-sm;
@apply block w-full rounded-md border-0 bg-white py-3 text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 placeholder:text-gray-400 focus:ring-2 focus:ring-inset focus:ring-indigo-600;
}
</style>
Loading

0 comments on commit a9982f0

Please sign in to comment.