Skip to content

Commit 1bc7e2a

Browse files
authored
fix(auth): revamp auth (#204)
1 parent d3ef5d7 commit 1bc7e2a

File tree

86 files changed

+1536
-4544
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

86 files changed

+1536
-4544
lines changed

app/auth.d.ts

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import type { Admin } from '~~/server/db/schema';
2+
3+
declare module '#auth-utils' {
4+
interface User extends Admin {}
5+
}
6+
7+
export {};

app/components/HandleFlexStrip.vue

-26
This file was deleted.

app/components/Onboarding/KeyInput.vue

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script setup lang="ts">
22
const emits = defineEmits<{
3-
done: [string];
3+
done: [string, boolean];
44
}>();
55
66
const key = ref('');
@@ -11,12 +11,12 @@ const verify = async () => {
1111
if (!key.value) return;
1212
try {
1313
isVerifying.value = true;
14-
const response = await $fetch<{ result: boolean }>('/api/onboarding/validate-key', {
14+
const response = await $fetch<{ result: boolean; registrationNeeded: boolean }>('/api/onboarding/validate-key', {
1515
method: 'POST',
1616
body: { key: key.value },
1717
});
1818
if (response.result) {
19-
emits('done', key.value);
19+
emits('done', key.value, response.registrationNeeded);
2020
} else {
2121
error.value = 'Invalid Key. Try again.';
2222
}
+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
<script setup lang="ts">
2+
import { registerSchema, loginSchema } from '~~/shared/schemas/authentication';
3+
4+
const props = defineProps<{
5+
register: boolean;
6+
onboardingKey: string;
7+
}>();
8+
9+
const formSchema = toTypedSchema(props.register ? registerSchema : loginSchema);
10+
const { handleSubmit, errors, defineField } = useForm({
11+
validationSchema: formSchema,
12+
});
13+
14+
const loginError = ref<string>();
15+
16+
// @ts-expect-error
17+
const [firstName] = defineField('firstName');
18+
// @ts-expect-error
19+
const [lastName] = defineField('lastName');
20+
const [email] = defineField('email');
21+
const [password] = defineField('password');
22+
23+
const emits = defineEmits<{
24+
done: [];
25+
}>();
26+
27+
const submit = handleSubmit(async (validatedData) => {
28+
try {
29+
await $fetch(`/api/${props.register ? 'register' : 'login'}`, {
30+
method: 'POST',
31+
body: validatedData,
32+
headers: {
33+
'x-onboarding-token': props.onboardingKey,
34+
},
35+
});
36+
emits('done');
37+
} catch (e: any) {
38+
if (e.data.statusCode === 401) {
39+
loginError.value = e.data.message;
40+
} else {
41+
loginError.value = 'Something went wrong.';
42+
}
43+
}
44+
});
45+
</script>
46+
47+
<template>
48+
<div class="flex flex-col space-y-2">
49+
<div class="flex flex-col justify-center">
50+
<InputLabel class="text-center" label-class="text-xl" label="Personal Details" v-if="register" />
51+
<InputLabel class="text-center" label-class="text-xl" label="Log back in" v-else />
52+
<InputLabel
53+
class="text-center"
54+
label-class="!text-zinc-500"
55+
label="Registering as super admin for this instance."
56+
v-if="register"
57+
/>
58+
<InputLabel
59+
class="text-center"
60+
label-class="!text-zinc-500"
61+
label="Super admin already registered, log back in."
62+
v-else
63+
/>
64+
</div>
65+
<div class="flex space-x-2 w-full" v-if="register">
66+
<!-- @vue-expect-error -->
67+
<InputText class="w-1/2" placeholder="First Name" v-model="firstName" :error="errors['firstName']" />
68+
<!-- @vue-expect-error -->
69+
<InputText class="w-1/2" placeholder="Last Name" v-model="lastName" :error="errors['lastName']" />
70+
</div>
71+
<InputText class="w-full" placeholder="Email" v-model="email" :error="errors['email']" />
72+
73+
<InputText
74+
class="w-full"
75+
placeholder="Password"
76+
type-override="password"
77+
v-model="password"
78+
:error="errors['password']"
79+
/>
80+
<InputButton @click="submit">
81+
{{ register ? 'Save' : 'Continue' }}
82+
</InputButton>
83+
<InputLabel :error="loginError" v-if="loginError" />
84+
</div>
85+
</template>

app/components/admin/ApplicationRow.vue

+8-25
Original file line numberDiff line numberDiff line change
@@ -4,46 +4,29 @@ const props = defineProps<{
44
application: Application;
55
}>();
66
7-
const user = props.applicant.user;
8-
const resume = props.applicant.handles.find((h) => h.key == 'resume')?.value;
9-
const isResumeAvailable = Boolean(resume);
7+
const candidate = props.applicant.candidate;
108
</script>
119

1210
<template>
1311
<div
1412
class="flex bg-white border border-zinc-200 rounded-xl items-center justify-between py-2 px-4"
15-
v-if="props.applicant && user"
13+
v-if="props.applicant && candidate"
1614
>
1715
<div class="flex">
18-
<div class="flex items-center">
19-
<div class="w-10 h-10 mr-2">
20-
<img
21-
class="rounded-xl"
22-
:src="user.picture || undefined"
23-
width="36"
24-
height="36"
25-
:alt="`${user.firstName}'s Profile Picture'`"
26-
/>
27-
</div>
28-
<div class="font-medium text-zinc-800">
29-
<span class="font-bold">{{ user.firstName + ' ' + user.lastName }}</span
30-
><br />
31-
<span class="text-zinc-700">{{ user.email }}</span>
32-
</div>
16+
<div class="font-medium text-zinc-800">
17+
<span class="font-bold">
18+
{{ candidate.firstName + ' ' + candidate.lastName }}
19+
</span>
20+
<br />
21+
<span class="text-zinc-700">{{ candidate.email }}</span>
3322
</div>
3423
</div>
3524
<div class="flex items-center justify-between space-x-20">
36-
<div class="whitespace-nowrap">
37-
<HandleFlexStrip :handles="applicant.handles" />
38-
</div>
3925
<div class="whitespace-nowrap">
4026
<div class="text-left">
4127
{{ timeAgo(new Date(application.createdAt)) }}
4228
</div>
4329
</div>
44-
<InputButton variant="secondary" as="a" target="_blank" :href="resume" :disabled="!isResumeAvailable">
45-
View Resume
46-
</InputButton>
4730
</div>
4831
</div>
4932
</template>

app/components/admin/MemberCard.vue

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
<script setup lang="ts">
2-
import type { User } from '~~/server/db/schema';
2+
import type { Admin } from '~~/server/db/schema';
33
44
const props = defineProps<{
5-
member: User;
5+
member: Admin;
66
}>();
77
88
const { deleteData } = await useMembersRepository();
9-
const { profile } = useAuth();
9+
const { user: profile } = useUserSession();
1010
1111
const onRemove = () => {
1212
deleteData({ id: props.member.id });

app/components/admin/MembersAddAction.vue

+25-21
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
<script setup lang="ts">
2-
import type { User } from '~~/server/db/schema';
2+
import type { Admin } from '~~/server/db/schema';
33
import { watchDebounced } from '@vueuse/core';
44
55
const { postData, changing } = await useMembersRepository();
66
7-
const suggestedUsers = ref<User[]>();
7+
const suggestedAdmins = ref<Admin[]>();
88
99
const submit = async (id: string, closeFn: () => void) => {
1010
let success = false;
@@ -16,23 +16,23 @@ const submit = async (id: string, closeFn: () => void) => {
1616
}
1717
};
1818
19-
const userSearchQuery = ref<string>('');
20-
const fetchingUserSuggestions = ref(false);
19+
const adminSearchQuery = ref<string>('');
20+
const fetchingAdminSuggestions = ref(false);
2121
2222
watchDebounced(
23-
userSearchQuery,
23+
adminSearchQuery,
2424
async (q) => {
2525
try {
26-
fetchingUserSuggestions.value = true;
27-
suggestedUsers.value = await $fetch<User[]>('/api/user/lookup', {
26+
fetchingAdminSuggestions.value = true;
27+
suggestedAdmins.value = await $fetch<Admin[]>('/api/admin/lookup', {
2828
query: {
2929
q,
3030
},
3131
});
3232
} catch (error) {
33-
console.error('error fetching user suggestions', error);
33+
console.error('error fetching admin suggestions', error);
3434
} finally {
35-
fetchingUserSuggestions.value = false;
35+
fetchingAdminSuggestions.value = false;
3636
}
3737
},
3838
{ debounce: 500, maxWait: 1000 }
@@ -52,35 +52,39 @@ watchDebounced(
5252
type="text"
5353
class="input-custom"
5454
placeholder="Start searching to add members"
55-
v-model="userSearchQuery"
55+
v-model="adminSearchQuery"
5656
:disabled="changing"
5757
/>
5858
<div
5959
class="flex flex-col space-y-3 overflow-y-scroll no-scrollbar h-64 mt-3"
60-
v-if="suggestedUsers && suggestedUsers.length > 0"
60+
v-if="suggestedAdmins && suggestedAdmins.length > 0"
6161
>
62-
<div class="flex w-full justify-between p-2 border rounded-lg" v-for="user in suggestedUsers" :key="user.id">
62+
<div
63+
class="flex w-full justify-between p-2 border rounded-lg"
64+
v-for="admin in suggestedAdmins"
65+
:key="admin.id"
66+
>
6367
<div class="flex space-x-1 items-center">
64-
<img :src="user.picture" v-if="user.picture" class="w-10 h-10 rounded-full" />
68+
<img :src="admin.picture" v-if="admin.picture" class="w-10 h-10 rounded-full" />
6569
<div class="flex flex-col text-sm">
66-
<span class="font-bold">{{ user.firstName }} {{ user.lastName }}</span>
67-
<span>{{ user.email }}</span>
70+
<span class="font-bold">{{ admin.firstName }} {{ admin.lastName }}</span>
71+
<span>{{ admin.email }}</span>
6872
</div>
6973
</div>
70-
<InputButton size="sm" variant="outline" @click="submit(user.id, close)" :loading="changing"
74+
<InputButton size="sm" variant="outline" @click="submit(admin.id, close)" :loading="changing"
7175
>Add</InputButton
7276
>
7377
</div>
7478
</div>
7579
<div class="h-64 flex w-full justify-center items-center" v-else>
76-
<span class="text-center" v-if="userSearchQuery && !fetchingUserSuggestions">
77-
<span class="font-bold">No User Found</span><br />
78-
<span class="text-xs">User has to login atleast once to be added.</span>
80+
<span class="text-center" v-if="adminSearchQuery && !fetchingAdminSuggestions">
81+
<span class="font-bold">No Admin Found</span><br />
82+
<span class="text-xs">Admin has to login atleast once to be added.</span>
7983
</span>
80-
<span class="text-center" v-else-if="!userSearchQuery">
84+
<span class="text-center" v-else-if="!adminSearchQuery">
8185
<span class="font-bold">Start typing to see suggestions.</span><br />
8286
<span class="text-xs">
83-
Any user added will be able to see / create job postings and see / manage all the applicants.
87+
Any admin added will be able to see / create job postings and see / manage all the applicants.
8488
</span>
8589
</span>
8690
</div>
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<script setup lang="ts">
2+
import { useVModel } from '@vueuse/core';
3+
import type { SelectableOption } from '~~/shared/types/general';
4+
5+
const { data: reviewTags } = await useReviewTagsRepository();
6+
7+
const options: SelectableOption[] = reviewTagGroupVsIndex
8+
.flatMap((_, i) => reviewTags.value.filter((rt) => rt.parent === i))
9+
.map((rt) => ({
10+
id: rt.id,
11+
title: rt.title,
12+
logo: 'material-symbols:circle',
13+
logoClass: `text-${reviewTagColorVsIndex[rt.parent]}-200 rounded-full border border-${reviewTagColorVsIndex[rt.parent]}-600`,
14+
}));
15+
16+
const props = defineProps<{
17+
modelValue?: number;
18+
}>();
19+
20+
const selectedTag = useVModel(props, 'modelValue');
21+
</script>
22+
23+
<template>
24+
<AbstractDropdownSingleSelect :options title="Select Tag" v-model="selectedTag" />
25+
</template>

0 commit comments

Comments
 (0)