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
@@ -1,7 +1,7 @@
'use client';

import React from 'react';
import StaffCard from './StaffCard';
import StaffCard from '../components/StaffCard';

interface User {
user_id: number;
Expand Down Expand Up @@ -36,18 +36,18 @@ export const teamMembers = mockUsers.filter(u => !u.is_admin);

export default function AccountsPage() {
return (
<div>
<div className="!p-6">
<h1 className="![font-family:var(--font-heading)] !text-[length:var(--font-size-heading-1)] !font-semibold">Accounts</h1>
<h3 className="![font-family:var(--font-heading)] !text-[length:var(--font-size-heading-3)] !font-semibold">Core BRANCH Facilitation Team</h3>
<div className="grid grid-cols-3 md:grid-cols-7 gap-3 !pt-3 !pb-7">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 !pt-3 !pb-7">
{facilitationTeam.map(user => (
<StaffCard key={user.user_id} name={user.name} />
<StaffCard key={user.user_id} name={user.name} email={user.email} />
))}
</div>
<h3 className="![font-family:var(--font-heading)] !text-[length:var(--font-size-heading-3)] !font-semibold">BRANCH Team Members</h3>
<div className="grid grid-cols-3 md:grid-cols-7 gap-3 !pt-3 !pb-7">
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3 !pt-3 !pb-7">
{teamMembers.map(user => (
<StaffCard key={user.user_id} name={user.name} />
<StaffCard key={user.user_id} name={user.name} email={user.email} />
))}
</div>
</div>
Expand Down
43 changes: 32 additions & 11 deletions apps/frontend/src/app/components/StaffCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,53 @@ import React from 'react';
import Image from 'next/image';
import { useState } from 'react';
import { PiUserCircleThin } from "react-icons/pi";
import { MdOutlineMail } from "react-icons/md";


interface StaffCardProps {
image?: string;
name: string;
title?: string;
email: string;
}


export default function StaffCard({
image,
name
name,
title,
email
}: StaffCardProps) {
const [imgError, setImgError] = useState(false);

return (
<div data-testid="staff-card" className="relative !w-full !flex flex-col items-center !p-3 !gap-1 overflow-hidden !border-1 !border-[var(--color-black-300)] !border-solid">
<div className="w-full aspect-square">
{(image && !imgError) ? (
<Image src={image} alt="Staff" width={120} height={120} className="object-cover w-full h-full" onError={() => setImgError(true)}/>
) : (
<div data-testid="staff-placeholder" className="w-full h-full flex items-center justify-center bg-[var(--color-primary-300)]">
<PiUserCircleThin size="100%" className="text-[var(--color-accent-dark-green)]" />
</div>
)}
<div data-testid="staff-card" className="relative !w-full !flex flex-row items-center !p-6 !gap-6 overflow-hidden !border-1 !border-[var(--color-black-300)] !border-solid rounded-lg">
<div className="w-[120px] h-[120px] shrink-0">
{(image && !imgError) ? (
<Image src={image} alt="Staff" width={120} height={120} className="object-cover w-full h-full rounded-full" onError={() => setImgError(true)}/>
) : (
<div data-testid="staff-placeholder" className="rounded-full w-full h-full flex items-center justify-center bg-[var(--color-primary-300)] overflow-hidden">
<PiUserCircleThin className="text-[var(--color-accent-dark-green)] !w-[158px] !h-[158px] shrink-0" />
</div>
)}
</div>

<div className="flex flex-col gap-4">
<h4 className="![font-family:var(--font-body)] !text-2xl font-normal !tracking-normal !normal-case break-words leading-tight">
{name}{title ? `, ${title}` : ''}
</h4>
<div className="flex flex-row items-center gap-2">
<MdOutlineMail className="text-black text-lg" size={24} />
<a
href={`https://mail.google.com/mail/?view=cm&to=${encodeURIComponent(email)}`}
target="_blank"
rel="noopener noreferrer"
className="!text-[var(--color-accent-dark-green)] !font-bold !underline"
>
{email}
</a>
</div>
<p className="![font-family:var(--font-body)] !text-[length:var(--font-size-callout)] !font-bold break-words w-full text-center !pt-1 !pb-2">{name}</p>
</div>
</div>
)
}
2 changes: 1 addition & 1 deletion apps/frontend/src/app/projects/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ export default function ProjectPage() {
) : (
<div className="!grid !grid-cols-2 !gap-3">
{members.slice(0, PREVIEW_STAFF).map((member) => (
<StaffCard key={member.user_id} name={member.name} />
<StaffCard key={member.user_id} name={member.name} email={member.email} />
))}
</div>
)}
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/test/components/AccountsPage.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { render, screen } from '../utils';
import AccountsPage, { facilitationTeam, teamMembers } from '@/app/components/AccountsPage';
import AccountsPage, { facilitationTeam, teamMembers } from '@/app/accounts/page';

describe('AccountsPage', () => {
it('renders the headings', () => {
Expand Down
35 changes: 26 additions & 9 deletions apps/frontend/test/components/StaffCard.test.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,50 @@
import { render, screen, fireEvent } from '../utils';
import StaffCard from '@/app/components/StaffCard';

describe ('StaffCard', () => {
describe('StaffCard', () => {
it('renders the placeholder image when no image given', () => {
render(<StaffCard name="name" />);
render(<StaffCard name="name" email="test@gmail.com" />);
expect(document.querySelector('[data-testid="staff-placeholder"]')).toBeInTheDocument();
});

it('renders the placeholder image when image given image has error', () => {
render(<StaffCard image="/" name="name" />);
it('renders the placeholder image when given image has error', () => {
render(<StaffCard image="/" name="name" email="test@gmail.com" />);
const img = document.querySelector('img');
fireEvent.error(img!);
expect(document.querySelector('[data-testid="staff-placeholder"]')).toBeInTheDocument();
});

it('renders the given image', () => {
render(<StaffCard image="/test.jpg" name="name" />);
render(<StaffCard image="/test.jpg" name="name" email="test@gmail.com" />);
const img = document.querySelector('img');
expect(img).toHaveAttribute('src', expect.stringContaining('test.jpg'));
});

it('renders the name', () => {
render(<StaffCard name="name" />);
render(<StaffCard name="name" email="test@gmail.com" />);
expect(screen.getByText('name')).toBeInTheDocument();
});

it('renders the name with title appended', () => {
render(<StaffCard name="Allen F. Shaughnessy" title="PharmD" email="test@gmail.com" />);
expect(screen.getByText('Allen F. Shaughnessy, PharmD')).toBeInTheDocument();
});

it('renders the name without title when title not given', () => {
render(<StaffCard name="name" email="test@gmail.com" />);
expect(screen.getByText('name')).toBeInTheDocument();
});

it('long name is wrapped', () => {
render(<StaffCard name="superduper longname" />);
render(<StaffCard name="superduper longname" email="test@gmail.com" />);
const name = screen.getByText('superduper longname');
expect(name).toHaveClass('break-words');
expect(name).toHaveClass('break-words');
});

it('renders the email with a mailto compose link', () => {
render(<StaffCard name="name" email="test@gmail.com" />);
const link = screen.getByText('test@gmail.com');
expect(link).toBeInTheDocument();
expect(link).toHaveAttribute('href', expect.stringContaining(encodeURIComponent('test@gmail.com')));
});
})
});
Loading