portfolio-page/src/components/sections/ContactSection.tsx

179 lines
6.9 KiB
TypeScript

// eslint-disable-next-line @typescript-eslint/no-deprecated
import { Mail, Send, Github, Linkedin } from 'lucide-react';
import { personalConfig } from '../../config/personal';
import { useLanguage } from '../../contexts/LanguageContext';
import { useScreenReaderAnnouncements } from '../../hooks/useScreenReaderAnnouncements';
interface ContactSectionProps {
title?: string;
subtitle?: string;
connectTitle?: string;
connectDescription?: string;
buttonText?: string;
socialTitle?: string;
availabilityText?: string;
responseTimeLabel?: string;
responseTimeValue?: string;
preferredContactLabel?: string;
preferredContactValue?: string;
locationLabel?: string;
locationValue?: string;
}
export default function ContactSection(props: ContactSectionProps = {}) {
const { texts: allTexts } = useLanguage();
const texts = allTexts.contact;
const { announce } = useScreenReaderAnnouncements();
const {
title = texts.title,
subtitle = texts.subtitle,
connectTitle = texts.connectTitle,
connectDescription = texts.connectDescription,
buttonText = texts.buttonText,
socialTitle = texts.socialTitle,
availabilityText = texts.availabilityText,
responseTimeLabel = texts.responseTimeLabel,
responseTimeValue = texts.responseTimeValue,
preferredContactLabel = texts.preferredContactLabel,
preferredContactValue = texts.preferredContactValue,
locationLabel = texts.locationLabel,
locationValue = texts.locationValue,
} = props;
// Enhanced email handler with better accessibility
const handleEmailClick = () => {
const email = getEmailAddress();
const subject = encodeURIComponent(texts.emailSubject);
const body = encodeURIComponent(texts.emailBody);
announce(texts.emailAnnouncement);
globalThis.location.href = `mailto:${email}?subject=${subject}&body=${body}`;
};
const getEmailAddress = () => {
const parts = ['freelancer', 'sascha-bach', 'de'];
return parts[0] + '@' + parts[1] + '.' + parts[2];
};
return (
<section id="contact" className="contact-section" aria-labelledby="contact-title">
<div className="contact-section__container">
{/* Section Header */}
<header className="contact-section__header">
<h2 id="contact-title" className="contact-section__title">
{title}
</h2>
<p className="contact-section__subtitle">
{subtitle}
</p>
</header>
{/* Contact Content Grid */}
<main id="contact-form" className="contact-section__grid">
{/* Let's Connect Card */}
<div className="contact-section__connect-card" role="region" aria-labelledby="connect-heading">
<div className="contact-section__connect-header">
<Mail
className="contact-section__email-icon"
aria-hidden="true"
/>
<div className="contact-section__connect-text">
<h3 id="connect-heading" className="contact-section__email-title">
{connectTitle}
</h3>
<p className="contact-section__email-description">
{connectDescription}
</p>
</div>
</div>
<button
onClick={handleEmailClick}
className="contact-section__email-button"
type="button"
aria-describedby="email-button-description"
>
<Send className="contact-section__button-icon" aria-hidden="true" />
<span className="contact-section__button-text">
{buttonText}
</span>
</button>
{/* Hidden description for screen readers */}
<div id="email-button-description" className="sr-only">
This button will open your default email client with a pre-filled message to {getEmailAddress()}
</div>
</div>
{/* Contact Info Sidebar */}
<aside className="contact-section__sidebar" aria-labelledby="info-heading">
<div className="contact-section__info-card">
<h3 id="info-heading" className="sr-only">Contact Information</h3>
<output className="contact-section__availability" aria-live="polite">
<div
className="contact-section__status-indicator"
aria-hidden="true"
></div>
<span className="contact-section__status-text">{availabilityText}</span>
</output>
<div className="contact-section__quick-facts">
<dl className="contact-section__fact-list">
<div className="contact-section__fact">
<dt className="contact-section__fact-label">{responseTimeLabel}</dt>
<dd className="contact-section__fact-value">{responseTimeValue}</dd>
</div>
<div className="contact-section__fact">
<dt className="contact-section__fact-label">{preferredContactLabel}</dt>
<dd className="contact-section__fact-value">{preferredContactValue}</dd>
</div>
<div className="contact-section__fact">
<dt className="contact-section__fact-label">{locationLabel}</dt>
<dd className="contact-section__fact-value">{locationValue}</dd>
</div>
</dl>
</div>
</div>
</aside>
{/* Social Contact Methods */}
<div className="contact-section__social-card" aria-labelledby="social-heading">
<h4 id="social-heading" className="contact-section__social-title">{socialTitle}</h4>
<ul className="contact-section__social-list">
<li className="contact-section__detail-item">
<Github className="contact-section__social-icon" aria-hidden="true" />
<a
href={personalConfig.social.github.url}
target="_blank"
rel="noopener noreferrer"
className="contact-section__detail-link"
aria-label={`${texts.githubLinkText} (opens in new tab)`}
>
{texts.githubLinkText}
</a>
</li>
<li className="contact-section__detail-item">
<Linkedin className="contact-section__social-icon" aria-hidden="true" />
<a
href={personalConfig.social.linkedin.url}
target="_blank"
rel="noopener noreferrer"
className="contact-section__detail-link"
aria-label={`${texts.linkedinLinkText} (opens in new tab)`}
>
{texts.linkedinLinkText}
</a>
</li>
</ul>
</div>
</main>
</div>
</section>
);
}