chore: heygermany customer project
This commit is contained in:
19
apps/website/hooks/backoffice/useBackOfficeLogin.ts
Normal file
19
apps/website/hooks/backoffice/useBackOfficeLogin.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { signInWithPassword } from "@/lib/auth"
|
||||
import { useMutation } from "@tanstack/react-query"
|
||||
import { useNavigate, useParams } from "@tanstack/react-router"
|
||||
|
||||
export const useBackOfficeLogin = () => {
|
||||
const navigate = useNavigate()
|
||||
const { lang } = useParams({ strict: false }) as { lang?: string }
|
||||
return useMutation({
|
||||
mutationFn: async ({ email, password }: { email: string; password: string }) => {
|
||||
return await signInWithPassword(email, password)
|
||||
},
|
||||
onSuccess: () => {
|
||||
navigate({ to: `/${lang || 'en'}/backoffice/candidates`, replace: true })
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('BackOffice login failed:', error)
|
||||
}
|
||||
})
|
||||
}
|
||||
10
apps/website/hooks/backoffice/useGetBackOfficeCandidate.ts
Normal file
10
apps/website/hooks/backoffice/useGetBackOfficeCandidate.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
|
||||
export const useGetBackOfficeCandidate = (candidateId: string) => {
|
||||
return useQuery({
|
||||
queryKey: ['backoffice', 'candidate', candidateId],
|
||||
queryFn: async () => await pikku().get(`/backoffice/candidate/:candidateId`, { candidateId }),
|
||||
enabled: !!candidateId
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
|
||||
export const useGetBackOfficeCandidateResult = (candidateId: string) => {
|
||||
return useQuery({
|
||||
queryKey: ['backoffice', 'candidate', candidateId, 'result'],
|
||||
queryFn: async () => await pikku().get(`/backoffice/candidate/:candidateId/result`, { candidateId }),
|
||||
enabled: !!candidateId
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
|
||||
export const useGetBackOfficeCandidates = () => {
|
||||
return useQuery({
|
||||
queryKey: ['backoffice', 'candidates'],
|
||||
queryFn: async () => await pikku().get('/backoffice/candidate', {})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
import { UpdateBackOfficeCandidateInput } from '@heygermany/functions/.pikku/http/pikku-http-wirings-map.gen.d.js'
|
||||
|
||||
type BackOfficeCandidatePatch = Omit<UpdateBackOfficeCandidateInput, 'candidateId'> & {
|
||||
analysisIssues?: string[]
|
||||
}
|
||||
|
||||
export const useUpdateBackOfficeCandidate = (candidateId: string) => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data: BackOfficeCandidatePatch) =>
|
||||
await pikku().patch("/backoffice/candidate/:candidateId", { candidateId, ...data }),
|
||||
onSuccess: () => {
|
||||
// Invalidate and refetch the candidate data
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['backoffice', 'candidate', candidateId]
|
||||
})
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['candidate', candidateId]
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
22
apps/website/hooks/backoffice/useUpdateCandidateEducation.ts
Normal file
22
apps/website/hooks/backoffice/useUpdateCandidateEducation.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import type { DB } from '@heygermany/sdk'
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
|
||||
type EducationUpdatePayload = Partial<Omit<DB.CandidateEducation, 'candidateId' | 'educationId' | 'createdAt' | 'lastUpdatedAt'>>
|
||||
|
||||
export const useUpdateCandidateEducation = (candidateId: string) => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data: EducationUpdatePayload) =>
|
||||
await pikku().patch("/backoffice/candidate/:candidateId/education", { candidateId, ...data }),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['backoffice', 'candidate', candidateId]
|
||||
})
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['candidate', candidateId]
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import type { DB } from '@heygermany/sdk'
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
|
||||
type ExperienceUpdatePayload = Partial<Omit<DB.CandidateExperience, 'candidateId' | 'experienceId' | 'createdAt' | 'lastUpdatedAt'>>
|
||||
|
||||
export const useUpdateCandidateExperience = (candidateId: string) => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data: ExperienceUpdatePayload) =>
|
||||
await pikku().patch("/backoffice/candidate/:candidateId/experience", { candidateId, ...data }),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['backoffice', 'candidate', candidateId]
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
22
apps/website/hooks/backoffice/useUpdateCandidateLanguage.ts
Normal file
22
apps/website/hooks/backoffice/useUpdateCandidateLanguage.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import type { DB } from '@heygermany/sdk'
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
|
||||
type LanguageUpdatePayload = Partial<Omit<DB.CandidateLanguage, 'candidateId' | 'languageId' | 'createdAt' | 'lastUpdatedAt'>>
|
||||
|
||||
export const useUpdateCandidateLanguage = (candidateId: string) => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data: LanguageUpdatePayload) =>
|
||||
await pikku().patch("/backoffice/candidate/:candidateId/language", { candidateId, ...data }),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['backoffice', 'candidate', candidateId]
|
||||
})
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['candidate', candidateId]
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
22
apps/website/hooks/backoffice/useUpdateCandidateLicense.ts
Normal file
22
apps/website/hooks/backoffice/useUpdateCandidateLicense.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import type { DB } from '@heygermany/sdk'
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
|
||||
type LicenseUpdatePayload = Partial<Omit<DB.CandidateLicense, 'candidateId' | 'licenseId' | 'createdAt' | 'lastUpdatedAt'>>
|
||||
|
||||
export const useUpdateCandidateLicense = (candidateId: string) => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async (data: LicenseUpdatePayload) =>
|
||||
await pikku().patch("/backoffice/candidate/:candidateId/license", { candidateId, ...data }),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['backoffice', 'candidate', candidateId]
|
||||
})
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['candidate', candidateId]
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import type { DB } from '@heygermany/sdk'
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query"
|
||||
|
||||
type UpdateDocumentVerificationInput = {
|
||||
documentId: string
|
||||
documentStatus: DB.DocumentStatus
|
||||
}
|
||||
|
||||
export const useUpdateDocumentVerification = (candidateId: string) => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ documentId, documentStatus }: UpdateDocumentVerificationInput) =>
|
||||
await pikku().patch("/backoffice/candidate/:candidateId/document/:documentId", {
|
||||
candidateId,
|
||||
documentId,
|
||||
documentStatus
|
||||
}),
|
||||
onSuccess: () => {
|
||||
// Invalidate and refetch the candidate data
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ['backoffice', 'candidate', candidateId]
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import type { DB } from '@heygermany/sdk'
|
||||
import { useQueryClient } from "@tanstack/react-query"
|
||||
|
||||
export const useUploadBackOfficeCandidateFiles = (candidateId: string, category: DB.CandidateDocumentType) => {
|
||||
const queryClient = useQueryClient()
|
||||
|
||||
const uploadFiles = async (files: File[]) => {
|
||||
if (!files.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const uploadUrls = await pikku().post('/candidate/:candidateId/document', {
|
||||
candidateId,
|
||||
documents: files.map((file) => ({
|
||||
fileName: file.name,
|
||||
size: file.size,
|
||||
contentType: file.type,
|
||||
category
|
||||
}))
|
||||
})
|
||||
|
||||
await Promise.all(uploadUrls.map(async ({ uploadUrl }: any, index: number) => {
|
||||
const response = await fetch(uploadUrl, {
|
||||
method: 'PUT',
|
||||
body: files[index],
|
||||
cache: 'no-cache',
|
||||
mode: 'cors',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': files[index].type,
|
||||
'Content-Disposition': 'inline'
|
||||
}
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`Failed to upload ${files[index].name}`)
|
||||
}
|
||||
}))
|
||||
|
||||
await Promise.all(uploadUrls.map(async ({ documentId }: any) => {
|
||||
await pikku().patch('/candidate/:candidateId/document/:documentId', {
|
||||
documentId,
|
||||
candidateId,
|
||||
uploaded: true
|
||||
})
|
||||
}))
|
||||
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['backoffice', 'candidate', candidateId]
|
||||
})
|
||||
}
|
||||
|
||||
const deleteFile = async (documentId: string) => {
|
||||
await pikku().delete('/candidate/:candidateId/document/:documentId', {
|
||||
candidateId,
|
||||
documentId
|
||||
})
|
||||
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ['backoffice', 'candidate', candidateId]
|
||||
})
|
||||
}
|
||||
|
||||
return { uploadFiles, deleteFile }
|
||||
}
|
||||
10
apps/website/hooks/candidate/useCandidateForm.ts
Normal file
10
apps/website/hooks/candidate/useCandidateForm.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { ApplicationCandidateData } from "@heygermany/sdk"
|
||||
import { useForm } from "react-hook-form"
|
||||
|
||||
export const useCandidateForm = (candidate: ApplicationCandidateData) => {
|
||||
const methods = useForm<ApplicationCandidateData>({
|
||||
defaultValues: candidate,
|
||||
})
|
||||
|
||||
return methods
|
||||
}
|
||||
18
apps/website/hooks/candidate/useGetCandidate.ts
Normal file
18
apps/website/hooks/candidate/useGetCandidate.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { pikku } from '@/pikku/http'
|
||||
import type { ApplicationCandidateData } from '@heygermany/sdk'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
|
||||
export const useGetCandidate = (candidateId?: string) => {
|
||||
return useQuery({
|
||||
queryKey: ['candidate'],
|
||||
queryFn: async (): Promise<ApplicationCandidateData> => {
|
||||
if (!candidateId) {
|
||||
return await pikku().get('/candidate')
|
||||
} else {
|
||||
return await pikku().get('/candidate/:candidateId', { candidateId })
|
||||
}
|
||||
},
|
||||
staleTime: 5 * 60 * 1000, // 5 minutes,
|
||||
retry: 0
|
||||
})
|
||||
}
|
||||
20
apps/website/hooks/company/useCompanyLogin.ts
Normal file
20
apps/website/hooks/company/useCompanyLogin.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { signInWithPassword } from "@/lib/auth"
|
||||
import { useMutation } from "@tanstack/react-query"
|
||||
import { useNavigate, useParams } from "@tanstack/react-router"
|
||||
|
||||
export const useCompanyLogin = () => {
|
||||
const navigate = useNavigate()
|
||||
const { lang } = useParams({ strict: false }) as { lang?: string }
|
||||
|
||||
return useMutation({
|
||||
mutationFn: async ({ email, password }: { email: string; password: string }) => {
|
||||
return await signInWithPassword(email, password)
|
||||
},
|
||||
onSuccess: () => {
|
||||
navigate({ to: `/${lang || 'en'}/company/candidates`, replace: true })
|
||||
},
|
||||
onError: (error) => {
|
||||
console.error('Company login failed:', error)
|
||||
}
|
||||
})
|
||||
}
|
||||
10
apps/website/hooks/company/useGetCompanyCandidate.ts
Normal file
10
apps/website/hooks/company/useGetCompanyCandidate.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
|
||||
export const useGetCompanyCandidate = (candidateId: string) => {
|
||||
return useQuery({
|
||||
queryKey: ['company', 'candidate', candidateId],
|
||||
queryFn: async () => await pikku().get('/company/candidate/:candidateId', { candidateId }),
|
||||
enabled: !!candidateId
|
||||
})
|
||||
}
|
||||
9
apps/website/hooks/company/useGetCompanyCandidates.ts
Normal file
9
apps/website/hooks/company/useGetCompanyCandidates.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
|
||||
export const useGetCompanyCandidates = () => {
|
||||
return useQuery({
|
||||
queryKey: ['company', 'candidates'],
|
||||
queryFn: async () => await pikku().get('/company/candidate', {})
|
||||
})
|
||||
}
|
||||
21
apps/website/hooks/useGetCandidateResult.ts
Normal file
21
apps/website/hooks/useGetCandidateResult.ts
Normal file
@@ -0,0 +1,21 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import { useQuery } from "@tanstack/react-query"
|
||||
import { CandidateResults } from "@heygermany/sdk"
|
||||
import { useI18n } from "@/context/i18n-provider"
|
||||
|
||||
export const useGetCandidateResults = (candidateId?: string) => {
|
||||
const { locale } = useI18n()
|
||||
return useQuery({
|
||||
queryKey: ['candidate', candidateId, 'results', locale],
|
||||
queryFn: async (): Promise<CandidateResults> => {
|
||||
try {
|
||||
const result = await pikku().get(`/candidate/:candidateId/results`, { candidateId: candidateId!, locale })
|
||||
return result
|
||||
} catch (error) {
|
||||
throw error
|
||||
}
|
||||
},
|
||||
enabled: !!candidateId,
|
||||
retry: false // Disable retry for debugging
|
||||
})
|
||||
}
|
||||
46
apps/website/hooks/useGetCountries.ts
Normal file
46
apps/website/hooks/useGetCountries.ts
Normal file
@@ -0,0 +1,46 @@
|
||||
import { pikku } from '@/pikku/http'
|
||||
import { useQuery } from '@tanstack/react-query'
|
||||
import { CountriesMap } from '@heygermany/sdk'
|
||||
import { SUPPORTED_COUNTRIES, SUPPORTED_COUNTRY_NAMES } from '@heygermany/sdk/config'
|
||||
import { useI18n } from '@/context/i18n-provider'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
export const useGetCountries = () => {
|
||||
const { locale } = useI18n()
|
||||
|
||||
const query = useQuery({
|
||||
queryKey: ['countries', locale],
|
||||
queryFn: async (): Promise<CountriesMap> => {
|
||||
return await pikku().get('/countries', { locale })
|
||||
},
|
||||
staleTime: 60 * 60 * 1000, // 1 hour
|
||||
})
|
||||
|
||||
const fallbackCountriesMap = useMemo(() => {
|
||||
return SUPPORTED_COUNTRIES.reduce((acc, code) => {
|
||||
acc[code] = SUPPORTED_COUNTRY_NAMES[code]
|
||||
return acc
|
||||
}, {} as CountriesMap)
|
||||
}, [])
|
||||
|
||||
const countriesMap = useMemo(() => {
|
||||
if (query.data && Object.keys(query.data).length > 0) {
|
||||
return query.data
|
||||
}
|
||||
|
||||
return fallbackCountriesMap
|
||||
}, [fallbackCountriesMap, query.data])
|
||||
|
||||
const getCountryNameFromAbbreviation = useMemo(() => {
|
||||
return (abbreviation: string | null | undefined): string => {
|
||||
if (!abbreviation) return 'N/A'
|
||||
return countriesMap[abbreviation] || abbreviation
|
||||
}
|
||||
}, [countriesMap])
|
||||
|
||||
return {
|
||||
...query,
|
||||
data: countriesMap,
|
||||
getCountryNameFromAbbreviation
|
||||
}
|
||||
}
|
||||
60
apps/website/hooks/useUploadCandidateFiles.ts
Normal file
60
apps/website/hooks/useUploadCandidateFiles.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { pikku } from "@/pikku/http"
|
||||
import type { DB } from '@heygermany/sdk'
|
||||
import { useQueryClient } from "@tanstack/react-query"
|
||||
import { UseFormTrigger } from "react-hook-form"
|
||||
|
||||
export const useUploadCandidateFiles = (candidateId: string, category: DB.CandidateDocumentType, trigger: UseFormTrigger<any>) => {
|
||||
const queryClient = useQueryClient()
|
||||
const isLocalDev =
|
||||
typeof window !== 'undefined' &&
|
||||
['localhost', '127.0.0.1'].includes(window.location.hostname)
|
||||
|
||||
const uploadFiles = async (files: File[]) => {
|
||||
const uploadUrls = await pikku().post('/candidate/:candidateId/document', {
|
||||
candidateId,
|
||||
documents: files.map(file => ({
|
||||
fileName: file.name,
|
||||
size: file.size,
|
||||
contentType: file.type,
|
||||
category
|
||||
}))
|
||||
})
|
||||
await Promise.all(uploadUrls.map(async ({ uploadUrl }: any, index: number) => {
|
||||
try {
|
||||
const response = await fetch(uploadUrl, {
|
||||
method: 'PUT',
|
||||
body: files[index],
|
||||
cache: 'no-cache',
|
||||
mode: 'cors',
|
||||
credentials: 'include',
|
||||
headers: {
|
||||
'Content-Type': files[index].type,
|
||||
'Content-Disposition': 'inline'
|
||||
}
|
||||
})
|
||||
if (!response.ok) {
|
||||
throw new Error(`Upload failed with status ${response.status}`)
|
||||
}
|
||||
} catch (error) {
|
||||
if (!isLocalDev) {
|
||||
throw error
|
||||
}
|
||||
console.warn('Skipping blob upload in local dev:', error)
|
||||
}
|
||||
}))
|
||||
await Promise.all(uploadUrls.map(async ({ documentId }: any) => {
|
||||
await pikku().patch('/candidate/:candidateId/document/:documentId', { documentId, candidateId, uploaded: true })
|
||||
}))
|
||||
await queryClient.invalidateQueries({ queryKey: ['candidate'] })
|
||||
setTimeout(() => {
|
||||
trigger()
|
||||
}, 100)
|
||||
}
|
||||
|
||||
const deleteFile = async (documentId: string) => {
|
||||
await pikku().delete('/candidate/:candidateId/document/:documentId', { candidateId, documentId })
|
||||
await queryClient.invalidateQueries({ queryKey: ['candidate'] })
|
||||
}
|
||||
|
||||
return { uploadFiles, deleteFile }
|
||||
}
|
||||
Reference in New Issue
Block a user