diff --git a/app/auth.d.ts b/app/auth.d.ts new file mode 100644 index 00000000..fc4226ee --- /dev/null +++ b/app/auth.d.ts @@ -0,0 +1,7 @@ +import type { Admin } from '~~/server/db/schema'; + +declare module '#auth-utils' { + interface User extends Admin {} +} + +export {}; diff --git a/app/components/HandleFlexStrip.vue b/app/components/HandleFlexStrip.vue deleted file mode 100644 index 7a5dfc50..00000000 --- a/app/components/HandleFlexStrip.vue +++ /dev/null @@ -1,26 +0,0 @@ - - - diff --git a/app/components/Onboarding/KeyInput.vue b/app/components/Onboarding/KeyInput.vue index 4b62b6a8..2e64afd7 100644 --- a/app/components/Onboarding/KeyInput.vue +++ b/app/components/Onboarding/KeyInput.vue @@ -1,6 +1,6 @@ + + diff --git a/app/components/admin/ApplicationRow.vue b/app/components/admin/ApplicationRow.vue index fa6481c8..c79682b9 100644 --- a/app/components/admin/ApplicationRow.vue +++ b/app/components/admin/ApplicationRow.vue @@ -4,46 +4,29 @@ const props = defineProps<{ application: Application; }>(); -const user = props.applicant.user; -const resume = props.applicant.handles.find((h) => h.key == 'resume')?.value; -const isResumeAvailable = Boolean(resume); +const candidate = props.applicant.candidate; diff --git a/app/components/admin/MemberCard.vue b/app/components/admin/MemberCard.vue index d85a64e0..0dc561d9 100644 --- a/app/components/admin/MemberCard.vue +++ b/app/components/admin/MemberCard.vue @@ -1,12 +1,12 @@ + + diff --git a/app/components/admin/ReviewTag/View.vue b/app/components/admin/ReviewTag/View.vue new file mode 100644 index 00000000..d52848f2 --- /dev/null +++ b/app/components/admin/ReviewTag/View.vue @@ -0,0 +1,114 @@ + + + diff --git a/app/composables/applications.ts b/app/composables/applications.ts index 6d107a50..9cd9034e 100644 --- a/app/composables/applications.ts +++ b/app/composables/applications.ts @@ -1,6 +1,6 @@ -import { type User, type UserHandle } from '~~/server/db/schema'; +import { type Candidate } from '~~/server/db/schema'; -export type Applicant = { user: User; handles: UserHandle[] }; +export type Applicant = { candidate: Candidate }; export type Applicants = Record; // applicantId <> applicant export type Application = { createdAt: Date; @@ -55,11 +55,3 @@ export function useApplications() { applications, }; } - -export function useApplicationStatus(postingId: string) { - const auth = useAuth(); - return useFetch('/api/application-status', { - query: { postingId }, - immediate: auth.isSignedIn.value, - }); -} diff --git a/app/composables/auth.ts b/app/composables/auth.ts index e875a9ea..1b7d6449 100644 --- a/app/composables/auth.ts +++ b/app/composables/auth.ts @@ -1,28 +1,24 @@ -export function useAuth() { - const session = useSessionState(); - const isSignedIn = computed(() => !!session.value?.profile); - const profile = computed(() => session.value?.profile); - - return { - session, - profile, - isSignedIn, - }; -} - -export function useSafeRedirectToLogin() { +export function useSafeRedirectToLogin(route: ReturnType) { const nextURLCookie = useCookie('oauth_next_url'); const redirectToLogin = (toPath: string | null = null) => { let nextURL = toPath; if (!toPath) { - const route = useRoute(); nextURL = route.fullPath; } nextURLCookie.value = nextURL; - return navigateTo('/login', { external: true }); + return navigateTo('/login'); + }; + + const redirectPostLogin = () => { + const nextURL = nextURLCookie.value; + nextURLCookie.value = undefined; // del cookie + if (nextURL) { + return navigateTo(nextURL); + } + return navigateTo('/admin/dashboard'); }; - return { redirectToLogin }; + return { redirectToLogin, redirectPostLogin }; } diff --git a/app/composables/members.ts b/app/composables/members.ts index 95519025..427ee487 100644 --- a/app/composables/members.ts +++ b/app/composables/members.ts @@ -1,6 +1,6 @@ import type { z } from 'zod'; import type { addMemberSchema, removeMemberSchema } from '~~/shared/schemas/setting'; -import type { User } from '~~/server/db/schema'; +import type { Admin } from '~~/server/db/schema'; type CreateMember = z.infer; type RemoveMember = z.infer; @@ -10,7 +10,7 @@ export function useMembersState() { } export async function useMembersRepository() { - return useObjectRepository({ + return useObjectRepository({ key: 'settings-members', fetchURL: '/api/settings/members', postURL: '/api/settings/members', diff --git a/app/composables/onboarding.ts b/app/composables/onboarding.ts index 14cd5ee6..7d5c6c17 100644 --- a/app/composables/onboarding.ts +++ b/app/composables/onboarding.ts @@ -3,16 +3,21 @@ import type { Step } from '~~/shared/types/general'; const steps: Step[] = [ { step: 1, + title: 'Personal Details', + icon: 'mdi:user-outline', + }, + { + step: 2, title: 'Logo', icon: 'octicon:upload-16', }, { - step: 2, + step: 3, title: 'Career Site', icon: 'icon-park-outline:config', }, { - step: 3, + step: 4, title: 'Done!', icon: 'mingcute:celebrate-line', }, diff --git a/app/composables/shortlisting.ts b/app/composables/shortlisting.ts new file mode 100644 index 00000000..7fac0393 --- /dev/null +++ b/app/composables/shortlisting.ts @@ -0,0 +1,31 @@ +import type { z } from 'zod'; +import type { ReviewTag } from '~~/server/db/schema'; +import type { + createReviewTagSchema, + deleteReviewTagSchema, + updateReviewTagSchema, +} from '~~/shared/schemas/review-tags'; + +type UpdateReviewTag = z.infer; +type CreateReviewTag = z.infer; +type DeleteReviewTag = z.infer; +export function useReviewTagsRepository() { + return useObjectRepository({ + key: 'review-tags', + fetchURL: '/api/review-tags', + postURL: '/api/review-tag', + updateURL: '/api/review-tag', + deleteURL: '/api/review-tag', + initFn: () => [], + }); +} + +// export function useReviewTagService() { +// const changing = ref(false); +// const updateReviewTag = async (options: ) => { +// try { +// changing.value = true; +// await +// } catch (error) {} +// }; +// } diff --git a/app/composables/state.ts b/app/composables/state.ts index d9af970b..fad8fac8 100644 --- a/app/composables/state.ts +++ b/app/composables/state.ts @@ -1,9 +1,4 @@ import { type CareerSiteConfig, type SEOConfig } from '~~/shared/schemas/setting'; -import type { Session } from '~~/shared/types/profile-types'; - -export function useSessionState() { - return useState('oauth_session'); -} export function useRemoteAssetBaseState() { return useState('remote-asset-base-url'); diff --git a/app/middleware/00.is-onboarded.global.ts b/app/middleware/00.is-onboarded.global.ts new file mode 100644 index 00000000..3d866d7c --- /dev/null +++ b/app/middleware/00.is-onboarded.global.ts @@ -0,0 +1,14 @@ +export default defineNuxtRouteMiddleware((to) => { + const onboardingStatus = useOnboardingStatus(); + const { redirectPostLogin } = useSafeRedirectToLogin(to); + + if (to.path.startsWith('/onboarding')) { + if (onboardingStatus.value) { + return redirectPostLogin(); + } + } else { + if (!onboardingStatus.value) { + return navigateTo('/onboarding'); + } + } +}); diff --git a/app/middleware/01.admin-auth.global.ts b/app/middleware/01.admin-auth.global.ts new file mode 100644 index 00000000..a30544f4 --- /dev/null +++ b/app/middleware/01.admin-auth.global.ts @@ -0,0 +1,23 @@ +const WHITELISTED_PATHS = ['/admin/login']; + +export default defineNuxtRouteMiddleware(async (to) => { + if (!to.path.startsWith('/admin')) return; + if (WHITELISTED_PATHS.includes(to.path)) return; + + console.log(to.path); + + const { redirectToLogin } = useSafeRedirectToLogin(to); + const { loggedIn } = useUserSession(); + + if (!loggedIn.value) { + return redirectToLogin(); + } + + const { user } = useUserSession(); + if (!user.value) { + throw createError({ + statusCode: 500, + message: 'User not available. Internal Error.', + }); + } +}); diff --git a/app/middleware/admin-auth.ts b/app/middleware/admin-auth.ts deleted file mode 100644 index d707200a..00000000 --- a/app/middleware/admin-auth.ts +++ /dev/null @@ -1,12 +0,0 @@ -export default defineNuxtRouteMiddleware(async (to) => { - const { profile, isSignedIn } = useAuth(); - const { redirectToLogin } = useSafeRedirectToLogin(); - - if (!isSignedIn.value) { - return redirectToLogin(to.fullPath); - } - - if (!profile.value?.isAdmin) { - return navigateTo('/'); - } -}); diff --git a/app/middleware/auth.ts b/app/middleware/auth.ts deleted file mode 100644 index 206899d1..00000000 --- a/app/middleware/auth.ts +++ /dev/null @@ -1,8 +0,0 @@ -export default defineNuxtRouteMiddleware((to) => { - const auth = useAuth(); - const { redirectToLogin } = useSafeRedirectToLogin(); - - if (!auth.isSignedIn) { - return redirectToLogin(to.fullPath); - } -}); diff --git a/app/middleware/is-onboarded.global.ts b/app/middleware/is-onboarded.global.ts deleted file mode 100644 index 0b892cd7..00000000 --- a/app/middleware/is-onboarded.global.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * If on onboarding page, - * - if onboarded, go to home - * - else do nothing, - * Else, - * - If not signed in, redirect to sign in - * - Else, navigate to onboarding page. - */ -export default defineNuxtRouteMiddleware((to) => { - const onboardingStatus = useOnboardingStatus(); - const auth = useAuth(); - const { redirectToLogin } = useSafeRedirectToLogin(); - - if (to.path.startsWith('/onboarding')) { - if (!auth.isSignedIn.value) { - return redirectToLogin(to.fullPath); - } - if (onboardingStatus.value) { - return navigateTo('/'); - } - return; - } - if (!onboardingStatus.value) { - return navigateTo('/onboarding'); - } -}); diff --git a/app/pages/admin/applications.vue b/app/pages/admin/applications.vue index 1acceb0f..3b088a8a 100644 --- a/app/pages/admin/applications.vue +++ b/app/pages/admin/applications.vue @@ -1,7 +1,6 @@