Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ describe('UserExperiencesList', () => {
});

describe('Basic rendering', () => {
it('should render empty fragment when no experiences provided', () => {
it('should render empty state with add button for owner when no experiences provided', () => {
const user = createUser();
renderComponent({
experiences: [],
Expand All @@ -109,6 +109,23 @@ describe('UserExperiencesList', () => {
user,
});

// Owner should see empty state with title and add button
expect(screen.getByText('Work Experience')).toBeInTheDocument();
expect(screen.getByText('Add your work experience')).toBeInTheDocument();
expect(
screen.getByRole('link', { name: /add your first work experience/i }),
).toBeInTheDocument();
});

it('should render empty fragment for non-owner when no experiences provided', () => {
const user = createUser({ id: 'otheruser', username: 'otheruser' });
renderComponent({
experiences: [],
title: 'Work Experience',
experienceType: UserExperienceType.Work,
user,
});

expect(screen.queryByText('Work Experience')).not.toBeInTheDocument();
});

Expand Down Expand Up @@ -461,13 +478,13 @@ describe('UserExperiencesList', () => {
user,
});

// The edit button is rendered as a link/button with href
const editLinks = screen.getAllByRole('link');
const editButton = editLinks.find((link) =>
link.getAttribute('href')?.includes('settings/profile/experience/work'),
);
expect(editButton).toBeTruthy();
expect(editButton?.getAttribute('href')).toBe(
// The edit button is rendered as a link/button with href to settings page
const editButton = screen.getByRole('link', {
name: 'Edit Work Experience',
});
expect(editButton).toBeInTheDocument();
expect(editButton).toHaveAttribute(
'href',
'https://app.daily.dev/settings/profile/experience/work',
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import type { ReactElement } from 'react';
import React, { useMemo } from 'react';
import type {
UserExperience,
UserExperienceType,
} from '../../../../graphql/user/profile';
import type { UserExperience } from '../../../../graphql/user/profile';
import { UserExperienceType } from '../../../../graphql/user/profile';
import {
Typography,
TypographyColor,
TypographyTag,
TypographyType,
} from '../../../../components/typography/Typography';
Expand All @@ -17,13 +16,71 @@ import {
ButtonSize,
ButtonVariant,
} from '../../../../components/buttons/Button';
import { MoveToIcon, EditIcon } from '../../../../components/icons';
import {
MoveToIcon,
PlusIcon,
EditIcon,
JobIcon,
TerminalIcon,
TourIcon,
} from '../../../../components/icons';
import { GraduationIcon } from '../../../../components/icons/Graduation';
import { MedalIcon } from '../../../../components/icons/Medal';
import { VolunteeringIcon } from '../../../../components/icons/Volunteering';
import { IconSize } from '../../../../components/Icon';
import Link from '../../../../components/utilities/Link';
import { useAuthContext } from '../../../../contexts/AuthContext';
import { webappUrl } from '../../../../lib/constants';
import type { PublicProfile } from '../../../../lib/user';
import { useProfilePreview } from '../../../../hooks/profile/useProfilePreview';
import type { IconProps } from '../../../../components/Icon';

const experienceTypeConfig: Record<
UserExperienceType,
{
icon: React.FC<IconProps>;
label: string;
heading: string;
subheading: string;
}
> = {
[UserExperienceType.Work]: {
icon: JobIcon,
label: 'work experience',
heading: 'Add your work experience',
subheading: "Show where you've worked and what you've accomplished",
},
[UserExperienceType.Education]: {
icon: GraduationIcon,
label: 'education',
heading: 'Add your education',
subheading: 'Share your academic background and achievements',
},
[UserExperienceType.Certification]: {
icon: MedalIcon,
label: 'certification',
heading: 'Add your certifications',
subheading: 'Showcase your professional certifications and credentials',
},
[UserExperienceType.OpenSource]: {
icon: TerminalIcon,
label: 'open source contribution',
heading: 'Add your open source work',
subheading: 'Highlight your contributions to open source projects',
},
[UserExperienceType.Project]: {
icon: TourIcon,
label: 'project',
heading: 'Add your projects',
subheading: 'Share your side projects and publications',
},
[UserExperienceType.Volunteering]: {
icon: VolunteeringIcon,
label: 'volunteering experience',
heading: 'Add your volunteering',
subheading: 'Share your community involvement and volunteer work',
},
};

interface UserExperienceListProps<T extends UserExperience> {
experiences: T[];
Expand Down Expand Up @@ -75,13 +132,64 @@ export function UserExperienceList<T extends UserExperience>({
[experiences],
);

if (!user || !experiences?.length) {
const hasExperiences = experiences?.length > 0;

if (!user) {
return null;
}

if (!hasExperiences && !isOwner) {
return null;
}

const showMoreUrl = `${webappUrl}${user.username}/${experienceType}`;
const editBaseUrl = `${webappUrl}settings/profile/experience/edit`;
const addUrl = `${editBaseUrl}?type=${experienceType}`;
const settingsUrl = `${webappUrl}settings/profile/experience/${experienceType}`;
const config = experienceTypeConfig[experienceType];
const IconComponent = config.icon;

if (!hasExperiences && isOwner) {
return (
<div className="flex flex-col gap-3 py-4">
{title && (
<Typography tag={TypographyTag.H2} type={TypographyType.Body} bold>
{title}
</Typography>
)}
<div className="flex flex-col items-center gap-4 rounded-16 bg-surface-float p-6">
<div className="flex size-14 items-center justify-center rounded-full bg-overlay-quaternary-cabbage">
<IconComponent size={IconSize.XLarge} />
</div>
<div className="flex flex-col items-center gap-1 text-center">
<Typography
type={TypographyType.Body}
color={TypographyColor.Primary}
bold
>
{config.heading}
</Typography>
<Typography
type={TypographyType.Footnote}
color={TypographyColor.Tertiary}
>
{config.subheading}
</Typography>
</div>
<Link href={addUrl} passHref>
<Button
tag="a"
variant={ButtonVariant.Secondary}
size={ButtonSize.Small}
icon={<PlusIcon />}
>
Add your first {config.label}
</Button>
</Link>
</div>
</div>
);
}

return (
<div className="flex flex-col gap-3 py-4">
Expand All @@ -90,7 +198,7 @@ export function UserExperienceList<T extends UserExperience>({
<Typography tag={TypographyTag.H2} type={TypographyType.Body} bold>
{title}
</Typography>
{settingsUrl && isOwner && (
{isOwner && (
<Link href={settingsUrl} passHref>
<Button
tag="a"
Expand Down