Sifa professional network frontend (Next.js, React, TailwindCSS)
sifa.id/
1'use client';
2
3import { useTranslations } from 'next-intl';
4import { TimelineSection, TimelineEntry, formatTimelineDate } from './timeline';
5import { EditableSection, EditableEntry, PROJECT_FIELDS } from '@/components/profile-editor';
6import { projectToValues, valuesToProject } from '@/components/profile-editor/section-converters';
7import { sortByDateDesc, dateRangeExtractor } from '@/lib/sort-by-date';
8import type { ProfileProject } from '@/lib/types';
9
10interface ProjectsSectionProps {
11 projects: ProfileProject[];
12 isOwnProfile?: boolean;
13}
14
15export function ProjectsSection({ projects, isOwnProfile }: ProjectsSectionProps) {
16 const t = useTranslations('sections');
17
18 if (!projects.length && !isOwnProfile) return null;
19
20 return (
21 <TimelineSection title={t('projects')} itemCount={projects.length}>
22 <EditableSection<ProfileProject>
23 sectionTitle={t('projects')}
24 profileKey="projects"
25 isOwnProfile={isOwnProfile}
26 fields={PROJECT_FIELDS}
27 toValues={projectToValues}
28 fromValues={
29 valuesToProject as (v: Record<string, string | boolean>) => Omit<ProfileProject, 'rkey'>
30 }
31 collection="id.sifa.profile.project"
32 maxVisible={3}
33 sortItems={(items) => sortByDateDesc(items, dateRangeExtractor)}
34 renderEntry={(proj, controls) => (
35 <EditableEntry
36 key={proj.rkey}
37 isOwnProfile={isOwnProfile}
38 onEdit={controls?.onEdit ?? (() => {})}
39 onDelete={controls?.onDelete ?? (() => {})}
40 entryLabel={proj.name}
41 >
42 <TimelineEntry
43 title={proj.name}
44 subtitle={proj.url ? proj.url.replace(/^https?:\/\/(www\.)?/, '') : ''}
45 dateRange={formatProjectDateRange(proj.startDate, proj.endDate)}
46 description={proj.description}
47 isLast={false}
48 />
49 </EditableEntry>
50 )}
51 />
52 </TimelineSection>
53 );
54}
55
56function formatProjectDateRange(start?: string, end?: string): string {
57 if (!start && !end) return '';
58 if (!start) return end ? formatTimelineDate(end) : '';
59 if (!end) return formatTimelineDate(start);
60 return `${formatTimelineDate(start)} - ${formatTimelineDate(end)}`;
61}