My personal website
1import { CardRole } from '@/components/CardRole/CardRole';
2import { Divider } from '@/components/Divider/Divider';
3import { Heading } from '@/components/Heading/Heading';
4import { Aside, Layout, Main } from '@/components/Layout/Layout';
5import { Link } from '@/components/Link/Link';
6import { Paragraph } from '@/components/Paragraph/Paragraph';
7import Section from '@/components/Section/Section';
8import TLDRProfile from '@/components/TLDRProfile/TLDRProfile';
9import { useProtopro } from '@/hooks/atproto';
10import type { JSX } from 'react';
11import { Helmet } from 'react-helmet-async';
12
13/**
14 * Work page component - displays CV/work history from AT Protocol PDS
15 *
16 * @returns JSX element with work page content
17 */
18export default function WorkPage(): JSX.Element {
19 const { data: profile, loading, error } = useProtopro();
20
21 // Split jobs into current and past
22 const currentJobs = profile?.jobHistory.filter((job) => !job.endDate) || [];
23 const pastJobs =
24 profile?.jobHistory
25 .filter((job) => job.endDate)
26 .sort((a, b) => {
27 // Sort by end date, newest first
28 const dateA = a.endDate ? new Date(a.endDate).getTime() : 0;
29 const dateB = b.endDate ? new Date(b.endDate).getTime() : 0;
30 return dateB - dateA;
31 }) || [];
32
33 const jsonLd = {
34 '@context': 'https://schema.org',
35 '@type': 'ProfilePage',
36 mainEntity: {
37 '@type': 'Person',
38 name: 'Barry Prendergast',
39 jobTitle: currentJobs[0]?.position || 'Product Designer',
40 description: 'Independent product designer and strategist',
41 url: 'https://renderg.host/work',
42 },
43 };
44
45 return (
46 <>
47 <Helmet>
48 <title>Work | Barry Prendergast</title>
49 <meta
50 name="description"
51 content="Independent product designer helping organisations deliver better products through clear thinking, practical design, and meaningful collaboration."
52 />
53 <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
54 </Helmet>
55
56 <Layout theme="default">
57 <Main>
58 <div className="flex flex-col gap-16">
59 {/* Heading */}
60 <Section>
61 <Heading level={2} size="base">
62 work / <Link href="/">renderg.host</Link>
63 </Heading>
64 </Section>
65
66 {/* Loading/Error States */}
67 {loading && (
68 <Section>
69 <Paragraph size="2xl">Loading profile...</Paragraph>
70 </Section>
71 )}
72
73 {error && (
74 <Section>
75 <Paragraph size="2xl">Error loading profile: {error}</Paragraph>
76 </Section>
77 )}
78
79 {/* Current Work Section */}
80 {!loading && !error && currentJobs.length > 0 && (
81 <Section>
82 <Heading level={2} size="lg">
83 Current roles
84 </Heading>
85
86 <div className="grid grid-cols-1 border-2 border-bones-black-20 dark:border-bones-white-20">
87 {currentJobs.map((job, index) => (
88 <>
89 <CardRole key={`current-${job.company}-${index}`} role={job} />
90 {index < currentJobs.length - 1 && <Divider />}
91 </>
92 ))}
93 </div>
94 </Section>
95 )}
96
97 {/* Past Work Section */}
98 {!loading && !error && pastJobs.length > 0 && (
99 <Section>
100 <Heading level={2} size="lg">
101 Previous roles
102 </Heading>
103
104 <div className="grid grid-cols-1 border-2 border-bones-black-20 dark:border-bones-white-20">
105 {pastJobs.map((job, index) => (
106 <>
107 <CardRole key={`past-${job.company}-${index}`} role={job} />
108 {index < pastJobs.length - 1 && <Divider />}
109 </>
110 ))}
111 </div>
112 </Section>
113 )}
114
115 {/* Exit */}
116 <Section>
117 <Paragraph size="md">
118 Return to <Link href="/">renderg.host</Link>
119 </Paragraph>
120 </Section>
121 </div>
122 </Main>
123
124 <Aside>
125 <TLDRProfile />
126 </Aside>
127 </Layout>
128 </>
129 );
130}