771 lines
26 KiB
TypeScript
771 lines
26 KiB
TypeScript
import type { ReactNode } from 'react'
|
|
import { useParams } from '@tanstack/react-router'
|
|
import {
|
|
Container,
|
|
Title,
|
|
Text,
|
|
Card,
|
|
Badge,
|
|
Group,
|
|
Stack,
|
|
Button,
|
|
Box,
|
|
Grid,
|
|
Loader,
|
|
Center,
|
|
Alert,
|
|
} from '@pikku/mantine/core'
|
|
import {
|
|
IconMapPin,
|
|
IconLanguage,
|
|
IconCalendar,
|
|
IconBriefcase,
|
|
IconAward,
|
|
IconMail,
|
|
IconInfoCircle,
|
|
IconSchool,
|
|
IconCheck,
|
|
} from '@tabler/icons-react'
|
|
import { useI18n } from '@/context/i18n-provider'
|
|
import { asI18n } from '@pikku/react'
|
|
import { useGetCompanyCandidate } from '@/hooks/company/useGetCompanyCandidate'
|
|
import { useGetCountries } from '@/hooks/useGetCountries'
|
|
import { CandidateProfileAvatar } from '@/components/company/CandidateProfileAvatar'
|
|
|
|
function SectionHeader({
|
|
icon,
|
|
title,
|
|
meta,
|
|
titleOrder = 3,
|
|
}: {
|
|
icon: ReactNode
|
|
title: string
|
|
meta?: ReactNode
|
|
titleOrder?: 3 | 4
|
|
}) {
|
|
return (
|
|
<Group justify="space-between" align="center" mb="lg">
|
|
<Group gap="xs" wrap="nowrap">
|
|
{icon}
|
|
<Title order={titleOrder}>{asI18n(title)}</Title>
|
|
</Group>
|
|
{meta}
|
|
</Group>
|
|
)
|
|
}
|
|
|
|
export default function CandidateDetailPage() {
|
|
const params = useParams({ strict: false })
|
|
const candidateId = params.candidateId as string
|
|
const t = useI18n()
|
|
const { getCountryNameFromAbbreviation } = useGetCountries()
|
|
const { isLoading, data: candidate } = useGetCompanyCandidate(candidateId)
|
|
const locale = t.locale || 'en'
|
|
|
|
// Format language level for display
|
|
const formatLanguageLevel = (level: string | null) => {
|
|
if (!level) return t('enums.languagelevel.none' as any)
|
|
return t(`enums.languagelevel.${level.toLowerCase()}` as any)
|
|
}
|
|
|
|
// Format profession for display
|
|
const formatProfession = (profession: string | null) => {
|
|
if (!profession) return t('common.na')
|
|
return t(`enums.nurserecognitiongermany.${profession.toLowerCase()}` as any)
|
|
}
|
|
|
|
const getRecognitionLikelihoodColor = (
|
|
likelihood: string | null | undefined
|
|
) => {
|
|
if (likelihood === 'high') return 'green'
|
|
if (likelihood === 'medium') return 'yellow'
|
|
if (likelihood === 'low') return 'red'
|
|
return 'gray'
|
|
}
|
|
|
|
const formatExperienceDate = (date: Date | string | null | undefined) => {
|
|
if (!date) return null
|
|
|
|
const parsedDate = new Date(date)
|
|
if (Number.isNaN(parsedDate.getTime())) return null
|
|
|
|
return new Intl.DateTimeFormat(locale, {
|
|
month: 'short',
|
|
year: 'numeric',
|
|
}).format(parsedDate)
|
|
}
|
|
|
|
const getExperienceMonthIndex = (
|
|
date: Date | string | null | undefined
|
|
): number | null => {
|
|
if (!date) return null
|
|
|
|
const parsedDate = new Date(date)
|
|
if (Number.isNaN(parsedDate.getTime())) return null
|
|
|
|
return parsedDate.getUTCFullYear() * 12 + parsedDate.getUTCMonth()
|
|
}
|
|
|
|
const getExperienceDurationMonths = (
|
|
startDate: Date | string | null | undefined,
|
|
endDate: Date | string | null | undefined
|
|
): number | null => {
|
|
const startMonth = getExperienceMonthIndex(startDate)
|
|
const endMonth = getExperienceMonthIndex(endDate || new Date())
|
|
|
|
if (
|
|
startMonth === null ||
|
|
endMonth === null ||
|
|
endMonth < startMonth
|
|
) {
|
|
return null
|
|
}
|
|
|
|
return endMonth - startMonth + 1
|
|
}
|
|
|
|
const formatExperienceDuration = (
|
|
startDate: Date | string | null | undefined,
|
|
endDate: Date | string | null | undefined
|
|
) => {
|
|
const totalMonths = getExperienceDurationMonths(startDate, endDate)
|
|
if (totalMonths === null) return null
|
|
|
|
const years = Math.floor(totalMonths / 12)
|
|
const months = totalMonths % 12
|
|
const parts: string[] = []
|
|
|
|
if (years > 0) {
|
|
parts.push(
|
|
`${years} ${t(
|
|
years === 1
|
|
? 'company.candidates.duration.year'
|
|
: 'company.candidates.duration.years'
|
|
)}`
|
|
)
|
|
}
|
|
|
|
if (months > 0) {
|
|
parts.push(
|
|
`${months} ${t(
|
|
months === 1
|
|
? 'company.candidates.duration.month'
|
|
: 'company.candidates.duration.months'
|
|
)}`
|
|
)
|
|
}
|
|
|
|
return parts.length > 0 ? parts.join(' ') : null
|
|
}
|
|
|
|
const formatExperienceTimeline = (
|
|
startDate: Date | string | null | undefined,
|
|
endDate: Date | string | null | undefined
|
|
) => {
|
|
const start = formatExperienceDate(startDate)
|
|
const end = endDate
|
|
? formatExperienceDate(endDate)
|
|
: start
|
|
? t('company.candidate.experience.present' as any)
|
|
: null
|
|
|
|
if (start && end) return `${start} - ${end}`
|
|
return start || end || t('common.na')
|
|
}
|
|
|
|
const formatExperiencePeriod = (
|
|
startDate: Date | string | null | undefined,
|
|
endDate: Date | string | null | undefined
|
|
) => {
|
|
const timeline = formatExperienceTimeline(startDate, endDate)
|
|
const duration = formatExperienceDuration(startDate, endDate)
|
|
|
|
return duration ? `${timeline} · ${duration}` : timeline
|
|
}
|
|
|
|
const formatFacilityType = (facilityType: string | null | undefined) => {
|
|
if (!facilityType) return t('common.na')
|
|
|
|
return facilityType
|
|
.split('_')
|
|
.filter(Boolean)
|
|
.map((segment) => segment.charAt(0).toUpperCase() + segment.slice(1))
|
|
.join(' ')
|
|
}
|
|
|
|
const getExperienceLocation = (
|
|
city: string | null | undefined,
|
|
country: string | null | undefined
|
|
) => {
|
|
const locationParts = [
|
|
city,
|
|
country
|
|
? getCountryNameFromAbbreviation(country) || country
|
|
: null,
|
|
].filter(Boolean)
|
|
|
|
return locationParts.length > 0
|
|
? locationParts.join(', ')
|
|
: null
|
|
}
|
|
|
|
const formatExperienceSummary = (
|
|
city: string | null | undefined,
|
|
country: string | null | undefined,
|
|
facilityType: string | null | undefined
|
|
) => {
|
|
const parts = [
|
|
getExperienceLocation(city, country),
|
|
facilityType ? formatFacilityType(facilityType) : null,
|
|
].filter(Boolean)
|
|
|
|
return parts.length > 0 ? parts.join(' · ') : t('common.na')
|
|
}
|
|
|
|
const formatExperienceDepartments = (
|
|
department: string | null | undefined
|
|
) => {
|
|
if (!department) return null
|
|
|
|
const departments = department
|
|
.split(',')
|
|
.map((entry) => entry.trim())
|
|
.filter(Boolean)
|
|
.slice(0, 3)
|
|
|
|
return departments.length > 0 ? departments.join(', ') : null
|
|
}
|
|
|
|
const formatHomeCountryQualification = (qualification: string | null) => {
|
|
if (!qualification) return t('common.na')
|
|
return t(
|
|
`enums.nurserecognitionhomecountry.${qualification.toLowerCase()}` as any
|
|
)
|
|
}
|
|
|
|
const formatEducationSummary = (
|
|
program: string | null | undefined,
|
|
institution: string | null | undefined
|
|
) => {
|
|
const educationParts = [program, institution].filter(Boolean)
|
|
return educationParts.length > 0
|
|
? educationParts.join(' · ')
|
|
: t('common.na')
|
|
}
|
|
|
|
const formatEducationCountry = (country: string | null | undefined) =>
|
|
country ? getCountryNameFromAbbreviation(country) || country : t('common.na')
|
|
|
|
if (isLoading) {
|
|
return (
|
|
<Center h={400}>
|
|
<Loader size="lg" />
|
|
</Center>
|
|
)
|
|
}
|
|
|
|
if (!candidate) {
|
|
return (
|
|
<Container size="xl" py="xl">
|
|
<Alert color="red" title={t('company.candidate.notfound.title')}>
|
|
{t('company.candidate.notfound.message')}
|
|
</Alert>
|
|
</Container>
|
|
)
|
|
}
|
|
|
|
const experiences = candidate.experience.filter((experience: any) =>
|
|
Boolean(
|
|
experience.roleTitle ||
|
|
experience.employerName ||
|
|
experience.department ||
|
|
experience.country ||
|
|
experience.city ||
|
|
experience.facilityType ||
|
|
experience.startDate ||
|
|
experience.endDate
|
|
)
|
|
)
|
|
const education = candidate.education
|
|
const hasExperienceDetails = experiences.length > 0
|
|
const hasEducationDetails = Boolean(
|
|
candidate.qualificationStatusHomeCountry ||
|
|
education?.program ||
|
|
education?.institution ||
|
|
education?.country ||
|
|
typeof education?.nursingRelatedDegree === 'boolean'
|
|
)
|
|
const sectionCardStyle = {
|
|
borderColor: 'var(--mantine-color-gray-2)',
|
|
}
|
|
const contactEmailHref = `mailto:info@hey-germany.com?subject=${encodeURIComponent(
|
|
`${t('company.candidate.contact.emailsubject')}: ${candidate.name} (${candidate.candidateId})`
|
|
)}&body=${encodeURIComponent(
|
|
`${t('company.candidate.contact.emailbody')}\n\n${t('company.candidates.candidate')}: ${candidate.name}\n${t('company.candidate.contact.emailcandidateid')}: ${candidate.candidateId}\n`
|
|
)}`
|
|
|
|
return (
|
|
<Box style={{ minHeight: 'calc(100vh - 80px)' }} suppressHydrationWarning>
|
|
<Container size="xl" py="xl" suppressHydrationWarning>
|
|
{/* Profile Header Card */}
|
|
<Card
|
|
shadow="sm"
|
|
padding="xl"
|
|
radius="md"
|
|
withBorder
|
|
mb="xl"
|
|
style={sectionCardStyle}
|
|
suppressHydrationWarning
|
|
>
|
|
<Group gap="xl" wrap="nowrap" align="flex-start">
|
|
<CandidateProfileAvatar
|
|
countryCode={candidate.countryEducation}
|
|
imageBorderWidth={4}
|
|
badgeBorderWidth={4}
|
|
badgeOffset={-8}
|
|
badgeSize={48}
|
|
iconSize={64}
|
|
name={candidate.name}
|
|
profileImageUrl={candidate.profileImageUrl}
|
|
size={128}
|
|
/>
|
|
|
|
{/* Info */}
|
|
<Box style={{ flex: 1 }}>
|
|
<Title order={1} mb="xs">
|
|
{asI18n(candidate.name)}
|
|
</Title>
|
|
<Text size="lg" c="gray.7" mb="md">
|
|
{formatProfession(candidate.qualificationStatusGermany)}
|
|
</Text>
|
|
{candidate.recognitionLikelihood && (
|
|
<Badge
|
|
size="md"
|
|
color={getRecognitionLikelihoodColor(
|
|
candidate.recognitionLikelihood
|
|
)}
|
|
variant="light"
|
|
mb="lg"
|
|
>
|
|
{asI18n(`${t(
|
|
`enums.recognitionlikelihood.${candidate.recognitionLikelihood}` as any
|
|
)} ${t('company.candidate.badge.recognitionlikelihood')}`)}
|
|
</Badge>
|
|
)}
|
|
|
|
<Grid gutter="md">
|
|
<Grid.Col span={{ base: 12, sm: 6 }}>
|
|
<Group gap="xs">
|
|
<IconMapPin size={18} color="var(--mantine-color-gray-6)" />
|
|
<Text size="sm" c="gray.7">
|
|
{asI18n(`${getCountryNameFromAbbreviation(
|
|
candidate.countryEducation
|
|
) || t('common.na')}${candidate.livingInGermany ? ` (${t('company.candidates.badge.ingermany')})` : ''}`)}
|
|
</Text>
|
|
</Group>
|
|
</Grid.Col>
|
|
<Grid.Col span={{ base: 12, sm: 6 }}>
|
|
<Group gap="xs">
|
|
<IconSchool size={18} color="var(--mantine-color-gray-6)" />
|
|
<Text size="sm" c="gray.7">
|
|
{asI18n(education?.program || t('common.na'))}
|
|
</Text>
|
|
</Group>
|
|
</Grid.Col>
|
|
<Grid.Col span={{ base: 12, sm: 6 }}>
|
|
<Group gap="xs">
|
|
<IconLanguage
|
|
size={18}
|
|
color="var(--mantine-color-gray-6)"
|
|
/>
|
|
<Text size="sm" c="gray.7">
|
|
{asI18n(`${t('company.candidates.german')} ${formatLanguageLevel(
|
|
candidate.languageSelfAssessmentLevel
|
|
)}`)}
|
|
</Text>
|
|
</Group>
|
|
</Grid.Col>
|
|
<Grid.Col span={{ base: 12, sm: 6 }}>
|
|
<Group gap="xs">
|
|
<IconCalendar
|
|
size={18}
|
|
color="var(--mantine-color-gray-6)"
|
|
/>
|
|
<Text size="sm" c="gray.7">
|
|
{candidate.age
|
|
? asI18n(`${candidate.age} ${t('company.candidate.yearsold')}`)
|
|
: t('common.na')}
|
|
</Text>
|
|
</Group>
|
|
</Grid.Col>
|
|
</Grid>
|
|
</Box>
|
|
</Group>
|
|
</Card>
|
|
|
|
{/* Main Content Grid */}
|
|
<Grid gutter="xl">
|
|
{/* Left Column */}
|
|
<Grid.Col span={{ base: 12, md: 8 }}>
|
|
<Stack gap="xl">
|
|
{/* Education Card */}
|
|
<Card
|
|
shadow="sm"
|
|
padding="lg"
|
|
radius="md"
|
|
withBorder
|
|
style={sectionCardStyle}
|
|
>
|
|
<SectionHeader
|
|
icon={<IconSchool size={18} />}
|
|
title={t('company.candidate.section.education')}
|
|
/>
|
|
|
|
{hasEducationDetails ? (
|
|
<Stack gap="md">
|
|
<div>
|
|
<Text size="sm" c="gray.6" mb={4}>
|
|
{t('company.candidate.field.qualificationlevel')}
|
|
</Text>
|
|
<Text fw={500}>
|
|
{asI18n(formatHomeCountryQualification(
|
|
candidate.qualificationStatusHomeCountry
|
|
))}
|
|
</Text>
|
|
</div>
|
|
<div>
|
|
<Text size="sm" c="gray.6" mb={4}>
|
|
{t('company.candidate.field.educationdegree')}
|
|
</Text>
|
|
<Text fw={500}>
|
|
{asI18n(formatEducationSummary(
|
|
education?.program,
|
|
education?.institution
|
|
))}
|
|
</Text>
|
|
</div>
|
|
<div>
|
|
<Text size="sm" c="gray.6" mb={4}>
|
|
{t('company.candidate.field.countryofeducation')}
|
|
</Text>
|
|
<Text fw={500}>
|
|
{asI18n(formatEducationCountry(
|
|
education?.country || candidate.countryEducation
|
|
))}
|
|
</Text>
|
|
</div>
|
|
<div>
|
|
<Text size="sm" c="gray.6" mb={4}>
|
|
{t('company.candidate.field.nursinglicense')}
|
|
</Text>
|
|
{candidate.hasVerifiedLicense ? (
|
|
<Group gap="xs">
|
|
<Text fw={500}>
|
|
{t('company.candidate.license.verified')}
|
|
</Text>
|
|
<IconCheck
|
|
size={18}
|
|
color="var(--mantine-color-green-6)"
|
|
/>
|
|
</Group>
|
|
) : (
|
|
<Text fw={500}>
|
|
{t('company.candidate.license.notprovided')}
|
|
</Text>
|
|
)}
|
|
</div>
|
|
</Stack>
|
|
) : (
|
|
<Text c="dimmed">{t('company.candidate.education.nodetails')}</Text>
|
|
)}
|
|
</Card>
|
|
|
|
{/* Languages Card */}
|
|
<Card
|
|
shadow="sm"
|
|
padding="lg"
|
|
radius="md"
|
|
withBorder
|
|
style={sectionCardStyle}
|
|
>
|
|
<SectionHeader
|
|
icon={<IconLanguage size={18} />}
|
|
title={t('company.candidate.section.languages')}
|
|
/>
|
|
{candidate.languagesSpoken &&
|
|
candidate.languagesSpoken.length > 0 && (
|
|
<Group gap="xs" mb="md">
|
|
{candidate.languagesSpoken.map((lang: any, index: number) => (
|
|
<Badge key={index} variant="outline" size="md">
|
|
{t(`enums.languagecode.${lang.toLowerCase()}` as any)}
|
|
</Badge>
|
|
))}
|
|
</Group>
|
|
)}
|
|
<Box
|
|
pt="md"
|
|
style={{ borderTop: '1px solid var(--mantine-color-gray-2)' }}
|
|
>
|
|
<Stack gap="md">
|
|
<div>
|
|
<Text size="sm" c="gray.6" mb={4}>
|
|
{t('company.candidate.field.germanlevel')}
|
|
</Text>
|
|
<Text fw={500}>
|
|
{asI18n(formatLanguageLevel(
|
|
candidate.languageSelfAssessmentLevel
|
|
))}
|
|
</Text>
|
|
</div>
|
|
<div>
|
|
<Text size="sm" c="gray.6" mb={4}>
|
|
{t('company.candidate.field.assessmenttype')}
|
|
</Text>
|
|
<Text fw={500}>
|
|
{candidate.languageCertificateProvided
|
|
? t('company.candidate.assessmenttype.certificate')
|
|
: t('company.candidate.assessmenttype.selfassessment')}
|
|
</Text>
|
|
</div>
|
|
</Stack>
|
|
</Box>
|
|
</Card>
|
|
|
|
<Card
|
|
shadow="sm"
|
|
padding="lg"
|
|
radius="md"
|
|
withBorder
|
|
style={sectionCardStyle}
|
|
>
|
|
<SectionHeader
|
|
icon={<IconBriefcase size={18} />}
|
|
title={t('company.candidate.section.workexperience')}
|
|
/>
|
|
|
|
{hasExperienceDetails ? (
|
|
<Stack gap={0}>
|
|
{experiences.map((experience: any, index: number) => (
|
|
<Box
|
|
key={`${experience.roleTitle || 'role'}-${experience.employerName || 'employer'}-${experience.startDate || index}`}
|
|
style={{
|
|
paddingTop: index === 0 ? 0 : 20,
|
|
paddingBottom:
|
|
index === experiences.length - 1 ? 0 : 20,
|
|
borderTop:
|
|
index === 0
|
|
? 'none'
|
|
: '1px solid var(--mantine-color-gray-2)',
|
|
}}
|
|
>
|
|
<Box
|
|
style={{
|
|
paddingLeft: 20,
|
|
marginLeft: 8,
|
|
borderLeft: '2px solid var(--mantine-color-gray-3)',
|
|
position: 'relative',
|
|
}}
|
|
>
|
|
<Box
|
|
style={{
|
|
position: 'absolute',
|
|
left: -7,
|
|
top: 6,
|
|
width: 12,
|
|
height: 12,
|
|
borderRadius: '50%',
|
|
background: 'var(--mantine-color-dark-9)',
|
|
}}
|
|
/>
|
|
<Stack gap={2}>
|
|
<Text fw={600} size="lg" c="dark.9">
|
|
{asI18n(experience.roleTitle || t('common.na'))}
|
|
</Text>
|
|
{experience.employerName ? (
|
|
<Text size="md" c="dark.7">
|
|
{asI18n(experience.employerName)}
|
|
</Text>
|
|
) : null}
|
|
{experience.department ? (
|
|
<Text size="sm" c="gray.6">
|
|
{asI18n(formatExperienceDepartments(
|
|
experience.department
|
|
) || t('common.na'))}
|
|
</Text>
|
|
) : null}
|
|
<Text size="sm" c="gray.6">
|
|
{asI18n(formatExperiencePeriod(
|
|
experience.startDate,
|
|
experience.endDate
|
|
) || t('common.na'))}
|
|
</Text>
|
|
<Text size="sm" c="gray.6">
|
|
{asI18n(formatExperienceSummary(
|
|
experience.city,
|
|
experience.country,
|
|
experience.facilityType
|
|
) || t('common.na'))}
|
|
</Text>
|
|
</Stack>
|
|
</Box>
|
|
</Box>
|
|
))}
|
|
</Stack>
|
|
) : (
|
|
<Text c="dimmed">{t('company.candidate.experience.nodetails' as any)}</Text>
|
|
)}
|
|
</Card>
|
|
|
|
{/* Recognition Status Card */}
|
|
<Card
|
|
shadow="sm"
|
|
padding="lg"
|
|
radius="md"
|
|
withBorder
|
|
style={sectionCardStyle}
|
|
>
|
|
<SectionHeader
|
|
icon={<IconAward size={18} />}
|
|
title={t('company.candidate.section.recognitionstatus')}
|
|
/>
|
|
<Stack gap="md">
|
|
<div>
|
|
<Group gap="xs" mb={4}>
|
|
<Text size="sm" c="gray.6">
|
|
{t('company.candidate.field.referenceprofession')}
|
|
</Text>
|
|
<IconInfoCircle
|
|
size={16}
|
|
color="var(--mantine-color-gray-6)"
|
|
/>
|
|
</Group>
|
|
<Text fw={500}>
|
|
{asI18n(formatProfession(candidate.qualificationStatusGermany))}
|
|
</Text>
|
|
</div>
|
|
<div>
|
|
<Text size="sm" c="gray.6" mb={4}>
|
|
{t('company.candidate.field.recognitionlikelihood')}
|
|
</Text>
|
|
{candidate.recognitionLikelihood ? (
|
|
<Badge
|
|
size="md"
|
|
color={getRecognitionLikelihoodColor(
|
|
candidate.recognitionLikelihood
|
|
)}
|
|
variant="light"
|
|
>
|
|
{t(
|
|
`enums.recognitionlikelihood.${candidate.recognitionLikelihood}` as any
|
|
)}
|
|
</Badge>
|
|
) : (
|
|
<Text fw={500}>{t('common.na')}</Text>
|
|
)}
|
|
</div>
|
|
</Stack>
|
|
</Card>
|
|
</Stack>
|
|
</Grid.Col>
|
|
|
|
{/* Right Column */}
|
|
<Grid.Col span={{ base: 12, md: 4 }}>
|
|
<Stack gap="xl">
|
|
{/* Personal Information Card */}
|
|
<Card
|
|
shadow="sm"
|
|
padding="lg"
|
|
radius="md"
|
|
withBorder
|
|
style={sectionCardStyle}
|
|
>
|
|
<SectionHeader
|
|
icon={<IconInfoCircle size={18} />}
|
|
title={t('company.candidate.section.personalinformation')}
|
|
titleOrder={4}
|
|
/>
|
|
<Stack gap="md">
|
|
<div>
|
|
<Text size="sm" c="gray.6" mb={4}>
|
|
{t('company.candidate.field.nationality')}
|
|
</Text>
|
|
<Text fw={500}>
|
|
{asI18n(getCountryNameFromAbbreviation(
|
|
candidate.nationality || candidate.countryEducation
|
|
) || t('common.na'))}
|
|
</Text>
|
|
</div>
|
|
|
|
<div>
|
|
<Text size="sm" c="gray.6" mb={4}>
|
|
{t('company.candidate.field.countryofresidence')}
|
|
</Text>
|
|
<Text fw={500}>
|
|
{asI18n(getCountryNameFromAbbreviation(
|
|
candidate.currentResidence
|
|
) || t('common.na'))}
|
|
</Text>
|
|
</div>
|
|
|
|
{candidate.stateWorkPreference &&
|
|
candidate.stateWorkPreference.length > 0 && (
|
|
<div>
|
|
<Text size="sm" c="gray.6" mb={4}>
|
|
{t('company.candidate.field.preferredlocations')}
|
|
</Text>
|
|
<Group gap="xs" mt="xs">
|
|
{candidate.stateWorkPreference.map((state: any, index: number) => (
|
|
<Badge key={index} variant="outline" size="sm">
|
|
{t(
|
|
`enums.germanstate.${state.toLowerCase().replace(/_/g, '-')}` as any
|
|
)}
|
|
</Badge>
|
|
))}
|
|
</Group>
|
|
</div>
|
|
)}
|
|
</Stack>
|
|
</Card>
|
|
|
|
{/* Contact Information Card */}
|
|
<Card
|
|
shadow="sm"
|
|
padding="lg"
|
|
radius="md"
|
|
withBorder
|
|
style={sectionCardStyle}
|
|
>
|
|
<SectionHeader
|
|
icon={<IconMail size={18} />}
|
|
title={t('company.candidate.section.contactinformation')}
|
|
titleOrder={4}
|
|
/>
|
|
<Stack gap="md">
|
|
<Text size="sm" c="gray.7">
|
|
{t('company.candidate.contact.emaildescription')}
|
|
</Text>
|
|
<Button
|
|
component="a"
|
|
href={contactEmailHref}
|
|
variant="default"
|
|
fullWidth
|
|
leftSection={<IconMail size={18} />}
|
|
styles={{
|
|
root: {
|
|
height: 48,
|
|
borderRadius: 10,
|
|
},
|
|
}}
|
|
>
|
|
{t('company.candidate.contact.emailcta')}
|
|
</Button>
|
|
</Stack>
|
|
</Card>
|
|
</Stack>
|
|
</Grid.Col>
|
|
</Grid>
|
|
</Container>
|
|
</Box>
|
|
)
|
|
}
|