Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(navigation): fallback on posting not found #169

Merged
merged 2 commits into from
Jan 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions app/components/Error/Fallback.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<script setup lang="ts">
import type { NuxtError } from '#app';

const props = defineProps<{
error: NuxtError;
}>();

const emits = defineEmits<{
clear: [string];
}>();

const heading = () => {
switch (props.error.statusCode) {
case 404:
return 'Not Found';
default:
return 'Something Went Wrong';
}
};
</script>

<template>
<div class="flex flex-col text-center items-center space-y-2">
<Icon name="fluent-color:dismiss-circle-16" class="w-32 h-32" />
<span class="text-xl font-bold font-noto">{{ heading() }}</span>
<span class="font-noto text-zinc-700" v-if="error.message">{{ error.message }}</span>
<InputButton variant="link" class="my-32" @click="emits('clear', '/')">Go Home</InputButton>
</div>
</template>
20 changes: 20 additions & 0 deletions app/components/Error/PostingNotFound.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<script setup lang="ts">
import type { NuxtError } from '#app';

defineProps<{
error: NuxtError;
}>();

const emits = defineEmits<{
clear: [string];
}>();
</script>

<template>
<div class="flex flex-col text-center items-center space-y-2">
<Icon name="fluent-color:beach-16" class="w-64 h-64" />
<span class="text-xl font-bold font-noto">Job posting not found.</span>
<span class="font-noto text-zinc-700">Provided URL is invalid, or posting has expired.</span>
<InputButton variant="link" class="my-32" @click="emits('clear', '/')">Explore active postings</InputButton>
</div>
</template>
39 changes: 39 additions & 0 deletions app/components/Error/index.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<script setup lang="ts">
import type { NuxtError } from '#app';

const route = useRoute();
const props = defineProps<{
error: NuxtError;
clientSide: boolean;
}>();

const error = props.error;
if (!error) {
// This will render this same component, but now with the error object
throw createError({
statusCode: 500,
message: 'Something went wrong',
});
}

const clear = async (redirect: string = '/') => {
if (props.clientSide) {
// Issue: remove external: true and see that navigation hangs. This is a temporary workaround.
await navigateTo(redirect, { external: true });
} else {
await clearError({ redirect });
}
};
</script>

<template>
<main class="flex flex-col w-full h-screen items-center justify-between">
<ErrorPostingNotFound
:error
@clear="clear"
v-if="route.path.startsWith('/postings/') && error.statusCode === 404"
/>
<ErrorFallback :error @clear="clear" v-else />
<VidurLogo class="h-6 my-8" />
</main>
</template>
1 change: 1 addition & 0 deletions app/components/Input/Button.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ const buttonVariants = cva(
outline: 'border border-zinc-300 bg-transparent hover:bg-zinc-100 text-zinc-900',
ghost: 'text-zinc-500 hover:text-zinc-900 bg-transparent',
secondary: 'bg-zinc-200 text-zinc-900 hover:bg-zinc-300',
link: 'text-blue-600 hover:text-blue-800 bg-transparent underline underline-offset-4',
},
size: {
default: 'h-8 px-4 py-2',
Expand Down
22 changes: 22 additions & 0 deletions app/components/VidurLogo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<template>
<svg width="185" height="48" viewBox="0 0 185 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M8.93016 0.266745C8.15312 0.637869 7.7704 1.09017 6.84259 2.79502C5.62484 5.03336 1.84402 11.876 1.15976 13.1053C0.173964 14.8565 0.0115976 15.4596 0 17.1645C0 18.6953 0.173964 19.4492 0.788638 20.5974C0.927809 20.8641 4.19834 26.257 8.06034 32.5893C15.7032 45.1379 15.7496 45.1959 17.5124 46.3788C18.5214 47.0515 19.8087 47.5734 21.1077 47.8401C21.9195 48.0025 22.9865 48.0141 29.5159 47.9909C36.8572 47.9561 37.008 47.9445 37.9242 47.6894C39.8842 47.1443 41.6934 45.9613 42.8764 44.4768C43.1779 44.0941 44.1985 42.5748 45.1495 41.1135C46.1005 39.6406 49.3478 34.6305 52.3632 29.9798C55.3786 25.3176 57.9649 21.2468 58.1156 20.9337C58.7999 19.4724 58.9275 17.3036 58.4056 15.7843C58.2664 15.3784 57.501 13.8591 56.7239 12.421C55.9353 10.9829 54.4972 8.33868 53.523 6.55265C52.5604 4.76662 51.5514 3.02697 51.2846 2.67905C50.7048 1.9252 49.6726 1.13656 48.6752 0.672659C47.2487 0.0231924 46.9471 0 39.6174 0C32.0674 0 31.9862 0.0115948 30.293 0.893013C28.8317 1.65846 28.101 2.51668 25.9787 6.01916C24.9581 7.70081 23.9839 9.37087 23.8099 9.73039C23.4156 10.519 23.3808 11.412 23.7055 12.1311C24.0998 13.0009 29.2028 21.2816 29.6203 21.7339C30.3625 22.5342 31.4295 22.8125 32.5545 22.4994C33.4475 22.2442 33.9694 21.5368 37.0312 16.5266C42.4125 7.68921 43.6882 5.62484 43.9318 5.35809C44.5116 4.73182 45.6018 4.40709 46.402 4.62744C47.3183 4.87099 47.7242 5.30011 48.5592 6.85419C53.9173 16.8977 54.2304 17.5124 54.3 18.1387C54.3464 18.6026 54.3116 18.8693 54.1377 19.2752C53.8941 19.8203 40.58 40.1045 40.1509 40.58C39.2463 41.5658 37.4139 41.5426 36.4513 40.5105C36.2889 40.3365 30.838 31.4643 24.355 20.8177C17.8719 10.1595 12.421 1.26414 12.2471 1.04378C11.4932 0.104376 9.99714 -0.24355 8.93016 0.266745Z"
fill="#09090B"
/>
<path d="M85.04 41L74.912 15.992H78.32L86.864 37.736L95.456 15.992H98.672L88.544 41H85.04Z" fill="#09090B" />
<path d="M103.194 41V15.992H106.458V41H103.194ZM103.194 10.76V5.96H106.458V10.76H103.194Z" fill="#09090B" />
<path
d="M111.967 28.568C111.967 26.2 112.447 24.04 113.407 22.088C114.399 20.104 115.759 18.52 117.487 17.336C119.215 16.152 121.183 15.56 123.391 15.56C125.471 15.56 127.327 16.12 128.959 17.24C130.623 18.328 131.919 19.656 132.847 21.224V5.96H136.111V37.064C136.111 37.512 136.207 37.848 136.399 38.072C136.591 38.264 136.879 38.376 137.263 38.408V41C136.623 41.096 136.127 41.128 135.775 41.096C135.103 41.064 134.511 40.792 133.999 40.28C133.487 39.768 133.231 39.208 133.231 38.6V36.152C132.239 37.784 130.895 39.08 129.199 40.04C127.503 41 125.743 41.48 123.919 41.48C122.191 41.48 120.591 41.128 119.119 40.424C117.679 39.72 116.415 38.76 115.327 37.544C114.271 36.328 113.439 34.952 112.831 33.416C112.255 31.848 111.967 30.232 111.967 28.568ZM132.847 32.408V24.68C132.431 23.528 131.759 22.488 130.831 21.56C129.903 20.6 128.847 19.848 127.663 19.304C126.511 18.728 125.359 18.44 124.207 18.44C122.863 18.44 121.647 18.728 120.559 19.304C119.471 19.848 118.527 20.6 117.727 21.56C116.959 22.52 116.367 23.608 115.951 24.824C115.535 26.04 115.327 27.288 115.327 28.568C115.327 29.912 115.551 31.192 115.999 32.408C116.479 33.624 117.151 34.712 118.015 35.672C118.879 36.6 119.871 37.32 120.991 37.832C122.111 38.344 123.327 38.6 124.639 38.6C125.471 38.6 126.335 38.44 127.231 38.12C128.127 37.8 128.975 37.368 129.775 36.824C130.607 36.248 131.295 35.576 131.839 34.808C132.383 34.04 132.719 33.24 132.847 32.408Z"
fill="#09090B"
/>
<path
d="M143.266 30.68V15.992H146.53V30.104C146.53 32.952 147.01 35.08 147.97 36.488C148.962 37.896 150.418 38.6 152.338 38.6C153.618 38.6 154.85 38.328 156.034 37.784C157.25 37.208 158.322 36.408 159.25 35.384C160.178 34.328 160.882 33.112 161.362 31.736V15.992H164.626V37.064C164.626 37.512 164.722 37.848 164.914 38.072C165.106 38.264 165.394 38.376 165.778 38.408V41C165.394 41.032 165.09 41.048 164.866 41.048C164.642 41.08 164.434 41.096 164.242 41.096C163.602 41.032 163.042 40.776 162.562 40.328C162.114 39.88 161.874 39.336 161.842 38.696L161.746 35.336C160.658 37.256 159.17 38.76 157.282 39.848C155.426 40.936 153.41 41.48 151.234 41.48C148.61 41.48 146.626 40.568 145.282 38.744C143.938 36.92 143.266 34.232 143.266 30.68Z"
fill="#09090B"
/>
<path
d="M184.486 18.872C182.31 18.936 180.39 19.544 178.726 20.696C177.094 21.848 175.942 23.432 175.27 25.448V41H172.006V15.992H175.078V21.992C175.942 20.232 177.078 18.808 178.486 17.72C179.926 16.632 181.446 16.024 183.046 15.896C183.366 15.864 183.638 15.848 183.862 15.848C184.118 15.848 184.326 15.864 184.486 15.896V18.872Z"
fill="#09090B"
/>
</svg>
</template>
4 changes: 2 additions & 2 deletions app/composables/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ export function useSeoConfigObjectState() {
export function useObjectState<T>(key: string, initFn?: () => T) {
const data = useState<T>(key, initFn);
const firstFetched = useState<boolean>(`${key}-first-fetch`, () => false);
const fetching = useState<boolean>(`${key}-fetching`);
const changing = useState<boolean>(`${key}-changing`);
const fetching = useState<boolean>(`${key}-fetching`, () => false);
const changing = useState<boolean>(`${key}-changing`, () => false);

const setData = (d: T) => {
firstFetched.value = true;
Expand Down
13 changes: 13 additions & 0 deletions app/error.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script setup lang="ts">
import type { NuxtError } from '#app';

defineProps<{
error: NuxtError;
}>();
</script>

<template>
<!-- This is masked into a component, since same thing needs to be called from default layout to handle errors generated during client side -->
<!-- This page only works when error is server side -->
<Error :error :client-side="false" />
</template>
8 changes: 8 additions & 0 deletions app/layouts/default.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<template>
<NuxtErrorBoundary>
<slot />
<template #error="error">
<Error :error :client-side="true" />
</template>
</NuxtErrorBoundary>
</template>
7 changes: 7 additions & 0 deletions app/pages/postings/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ const id = route.params.id as string;

const { data: posting } = await usePublicPostingRepository({ id });

if (!posting.value) {
throw createError({
statusCode: 404,
message: 'No such posting found. Maybe the posting has expired.',
});
}

const { data: careerSiteConfig } = useCareerSiteConfigObjectState();
const companyLogo = useRemoteAsset(careerSiteConfig.value.logo).url;

Expand Down
Loading