Skip to content

Commit 8eea90b

Browse files
authored
Merge pull request #127 from Code-the-Change-YYC/WEB-68-Create-a-new-Our-Team-page-and-add-tab-in-Navigation
Web 68 create a new our team page and add tab in navigation
2 parents 08020c6 + f32b7ce commit 8eea90b

19 files changed

+429
-22
lines changed

components/Avatar.jsx

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,39 @@
1+
/* eslint-disable indent */
2+
// please forgive me idk why it made me do this someone with different eslint config can fix this
13
import Image from 'next/image';
24
import { faLinkedin } from '@fortawesome/free-brands-svg-icons';
35
import FontAwesomeLink from './FontAwesomeLink';
6+
import { PageIdentifiers } from '../utils/flags';
47

58
const PROFILE_CONTAINER = 'flex flex-col items-center m-10';
69

7-
const Avatar = ({ name, linkedin, position, pfp, classes, prevRole }) => {
10+
const Avatar = ({ name, linkedin, position, pfp, classes, prevRole, profileContainerClasses = '', teamIdentifier }) => {
811
const img = 'https:' + pfp.fields.file.url;
12+
13+
const colorTheme =
14+
teamIdentifier === PageIdentifiers.INTERNAL_LEVEL_CONTAINER
15+
? 'text-[#00D3A9]'
16+
: teamIdentifier === PageIdentifiers.EXECUTIVE_LEVEL_CONTAINER
17+
? 'text-[#7055FD]'
18+
: '';
19+
920
return (
10-
<div className={PROFILE_CONTAINER}>
11-
<div className="w-28 h-28 sm:w-48 sm:h-48 rounded-full relative overflow-hidden">
21+
<div className={`${PROFILE_CONTAINER} ${profileContainerClasses}`}>
22+
<div className={`size-28 sm:size-44 md:size-48 rounded-full relative overflow-hidden`}>
1223
<Image src={img} alt={name} layout="fill" objectFit="contain" unoptimized={true} />
1324
</div>
14-
<h2 className={`text-[#7055FD] text-xs sm:text-base font-semibold mt-3 ${classes}`}>{name}</h2>
15-
<h2 className={`text-[#7055FD] text-xs sm:text-base font-medium mb-2 ${classes}`}>{position}</h2>
25+
<h2 className={`${colorTheme} text-xs sm:text-base font-semibold mt-3 ${classes}`}>{name}</h2>
26+
<h2 className={`${colorTheme} text-xs sm:text-base font-medium mb-2 ${classes}`}>{position}</h2>
1627
{prevRole && (
17-
<h2 className={`text-[#7055FD] text-xs sm:text-base font-medium mb-2 ${classes}`}>Previously: {prevRole}</h2>
28+
<h2
29+
className={`${colorTheme} w-28 text-center text-xs sm:text-base hidden sm:block font-medium mb-2 ${classes}`}
30+
>
31+
Previously: {prevRole}
32+
</h2>
33+
)}
34+
{linkedin && (
35+
<FontAwesomeLink colorTheme={colorTheme} username={linkedin} icon={faLinkedin} className={`${classes}`} />
1836
)}
19-
{linkedin && <FontAwesomeLink username={linkedin} icon={faLinkedin} />}
2037
</div>
2138
);
2239
};

components/EventsTeam.jsx

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
2+
// import React, { useState, useEffect } from 'react';
3+
import Avatar from './Avatar';
4+
// import { fetchContent } from '../api/apiRoot';
5+
6+
7+
const PROFILES_CONTAINER = 'bg-white flex flex-col items-center pt-5';
8+
const EXECUTIVE_LEVEL_CONTAINER = 'flex flex-wrap justify-center w-full gap-x-10 sm:gap-x-20 px-10';
9+
const DUMMY_PFP ="//i.pinimg.com/736x/dd/8b/a9/dd8ba98ba0b06489ac96f76b74fe7fc6.jpg";
10+
11+
const EventsTeam = () => {
12+
// use this when we use api for real
13+
// const [eventsTeam, setEventsTeam] = useState([]);
14+
// useEffect(() => {
15+
// fetchContent('eventsTeamMember').then((data) => setEventsTeam(data));
16+
// }, []);
17+
const eventsTeamLeads = [
18+
{
19+
name: 'Alice Johnson',
20+
position: 'Marketing Lead',
21+
prevRole: 'Social Media Manager',
22+
linkedin: 'alicejohnson',
23+
pfp: { fields: { file: { url: DUMMY_PFP } } },
24+
},
25+
{
26+
name: 'Bob Smith',
27+
position: 'Brand Strategist',
28+
linkedin: 'bobsmith',
29+
pfp: { fields: { file: { url: DUMMY_PFP } } },
30+
},
31+
];
32+
const eventsTeamMembers = [
33+
{
34+
name: 'Alice Johnson',
35+
position: 'Marketing Lead',
36+
linkedin: 'alicejohnson',
37+
pfp: { fields: { file: { url: DUMMY_PFP } } },
38+
},
39+
{
40+
name: 'Bob Smith',
41+
position: 'Brand Strategist',
42+
linkedin: 'bobsmith',
43+
pfp: { fields: { file: { url: DUMMY_PFP } } },
44+
},
45+
{
46+
name: 'Charlie Brown',
47+
position: 'SEO Specialist',
48+
linkedin: 'charliebrown',
49+
pfp: { fields: { file: { url: DUMMY_PFP } } },
50+
},
51+
];
52+
53+
return (
54+
<div>
55+
<div className={PROFILES_CONTAINER}>
56+
<div className={EXECUTIVE_LEVEL_CONTAINER}>
57+
{eventsTeamLeads.map((exec) => (
58+
<Avatar classes="!text-[#00D3A9]" profileContainerClasses='!mx-0 !flex-wrap' key={exec.name} {...exec} />
59+
))}
60+
</div>
61+
</div>
62+
<div className={PROFILES_CONTAINER}>
63+
<div className={EXECUTIVE_LEVEL_CONTAINER}>
64+
{eventsTeamMembers.map((exec) => (
65+
<Avatar key={exec.name}{...exec} profileContainerClasses='!mx-0 !flex-wrap' classes="!text-[#00D3A9]" />
66+
))}
67+
</div>
68+
</div>
69+
</div>
70+
);
71+
};
72+
73+
74+
export default EventsTeam;

components/FontAwesomeLink.jsx

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
1+
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
22

3-
const FontAwesomeLink = ({ username, icon, classes = "h-6 w-6 text-[#7055FD] cursor-pointer" }) => (
4-
<a target="_blank" href={`https://linkedin.com/in/${username}`} rel="noopener noreferrer">
5-
<FontAwesomeIcon className={classes} icon={icon} />
6-
</a>
7-
);
3+
const FontAwesomeLink = ({ username, colorTheme, icon, className }) => {
4+
const defaultClasses = 'size-6 transition-all duration-300 cursor-pointer';
5+
return (
6+
<a target="_blank" href={`https://linkedin.com/in/${username}`} rel="noopener noreferrer">
7+
<FontAwesomeIcon className={`${colorTheme} hover:size-7 ${defaultClasses} ${className}`} icon={icon} />
8+
</a>
9+
);
10+
};
811

912
export default FontAwesomeLink;

components/Heading.jsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,21 @@
11
import { UnderlineTypes } from '../utils/underlineType';
22

33
/* eslint-disable @next/next/no-img-element */
4-
const HEADING_CONTAINER = 'py-5 flex flex-col items-center';
54

65
const GREEN_LONG_UNDERLINE_DIR = '/svgs/long_heading_underline.svg';
76
const GREEN_SHORT_UNDERLINE_DIR = '/svgs/short_heading_underline.svg';
87
const PURPLE_SHORT_UNDERLINE_DIR = '/svgs/timeline/purple_heading_underline.svg';
98
const WHITE_SINGLE_LINE_DIR = '/svgs/white_long_underline.svg';
109
const WHITE_CURLY_LINE_DIR = '/svgs/white_alumni_underline.svg';
1110
const BEIGE_SHORT_UNDERLINE_DIR = '/svgs/beige_underline.svg';
11+
const PINK_UNDERLINE_DIR = '/svgs/pink_underline.svg';
1212

13-
const Heading = ({ classes, underlineType = UnderlineTypes.GREEN_SHORT_UNDERLINE, children }) => {
13+
const Heading = ({
14+
classes = '',
15+
// distanceFromTop = 0,
16+
underlineType = UnderlineTypes.GREEN_SHORT_UNDERLINE,
17+
children,
18+
}) => {
1419
const getUnderline = () => {
1520
switch (underlineType) {
1621
case UnderlineTypes.GREEN_LONG_UNDERLINE:
@@ -25,13 +30,15 @@ const Heading = ({ classes, underlineType = UnderlineTypes.GREEN_SHORT_UNDERLINE
2530
return WHITE_CURLY_LINE_DIR;
2631
case UnderlineTypes.BEIGE_SHORT_UNDERLINE:
2732
return BEIGE_SHORT_UNDERLINE_DIR;
33+
case UnderlineTypes.PINK_UNDERLINE:
34+
return PINK_UNDERLINE_DIR;
2835
}
2936
};
3037

3138
return (
32-
<div className={HEADING_CONTAINER}>
33-
<h1 className={`${classes} text-5xl font-semibold`}>{children}</h1>
34-
{underlineType !== 'None' && <img src={getUnderline()} alt="" />}
39+
<div className="relative inline-block text-center">
40+
<span className={`relative z-10 ${classes} text-5xl font-semibold`}>{children}</span>
41+
{underlineType !== 'None' && <img src={getUnderline()} alt="squiggly" className="w-4/5 mx-auto" />}
3542
</div>
3643
);
3744
};

components/InternalTeam.jsx

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
import Team from './Team';
2+
import { fetchContent } from '../api/apiRoot';
3+
import { useState, useEffect } from 'react';
4+
import { Tabs, TabsHeader, TabsBody, Tab, TabPanel } from '@material-tailwind/react';
5+
import Heading from './Heading';
6+
import { UnderlineTypes } from '../utils/underlineType';
7+
import { PageIdentifiers } from '../utils/flags';
8+
9+
const positionToGroupMap = {
10+
'Jr VP Marketing': 'Marketing',
11+
'VP Marketing': 'Marketing',
12+
'Jr VP Events': 'Events',
13+
'VP Events': 'Events',
14+
'Co President': 'Presidents',
15+
'Jr VP Design': 'Design',
16+
'VP Design': 'Design',
17+
'Jr VP Tech': 'Tech',
18+
'VP Tech': 'Tech',
19+
'VP External': 'External',
20+
'Jr VP External': 'External',
21+
};
22+
23+
const InternalTeam = () => {
24+
const [executives, setExecutives] = useState([]);
25+
const [groups, setGroups] = useState([]);
26+
const [activeTab, setActiveTab] = useState('');
27+
28+
useEffect(() => {
29+
fetchContent('adminTeamMember').then((data) => {
30+
const executivesWithGroups = data.map((exec) => ({
31+
...exec,
32+
group: positionToGroupMap[exec.position] || 'Other',
33+
}));
34+
35+
setExecutives(executivesWithGroups);
36+
37+
const uniqueGroups = executivesWithGroups
38+
.map((exec) => exec.group)
39+
.filter((group, index, self) => self.indexOf(group) === index);
40+
41+
setGroups(uniqueGroups);
42+
43+
if (uniqueGroups.length > 0) {
44+
setActiveTab(uniqueGroups[0]);
45+
}
46+
});
47+
}, []);
48+
49+
return (
50+
<>
51+
<div className="mb-12 flex justify-center gap-3">
52+
<Heading distanceFromTop={11} underlineType={UnderlineTypes.GREEN_SHORT_UNDERLINE}>
53+
Internal{' '}
54+
</Heading>
55+
<span className="text-5xl font-semibold">Team</span>
56+
</div>
57+
{groups.length > 0 && (
58+
<Tabs value={activeTab}>
59+
<TabsHeader className="overflow-x-auto grid place-items-center">
60+
<div className="flex flex-row gap-2">
61+
{groups.map((group) => (
62+
<Tab key={group} value={group} onClick={() => setActiveTab(group)}>
63+
<div
64+
className={`rounded-full px-4 py-2 font-medium hover:bg-[#00D3A9] hover:text-white transition-all duration-200
65+
${activeTab === group ? 'bg-[#00D3A9] text-white' : 'text-black'}
66+
`}
67+
>
68+
{group}
69+
</div>
70+
</Tab>
71+
))}
72+
</div>
73+
</TabsHeader>
74+
<TabsBody>
75+
{groups.map((group) => (
76+
<TabPanel key={group} value={group}>
77+
<Team
78+
teamIdentifier={PageIdentifiers.INTERNAL_LEVEL_CONTAINER}
79+
teamMembers={executives.filter((exec) => exec.group === group)}
80+
/>
81+
</TabPanel>
82+
))}
83+
</TabsBody>
84+
</Tabs>
85+
)}
86+
</>
87+
);
88+
};
89+
90+
export default InternalTeam;

components/MeetOurTeam.jsx

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import TextSection from '/components/TextSection.jsx';
2+
import Heading from '/components/Heading';
3+
import { UnderlineTypes } from '../utils/underlineType';
4+
import { useRef } from 'react';
5+
import InternalTeam from './InternalTeam';
6+
import TechnicalTeam from './TechnicalTeam';
7+
8+
const MEET_OUR_TEAM = 'flex flex-col bg-pink pt-10 z-0 w-full';
9+
const CONTENT_CONTAINER = 'flex flex-col pt-5 p-5 md:px-32';
10+
const MEET_OUR_AMAZING_TEAM_TITLE =
11+
'flex flex-wrap items-baseline gap-x-2 pt-5 justify-center w-fit mx-20 sm:mx-20 md:mx-auto lg:mx-auto';
12+
13+
const Button = ({ classes = '', children, targetRef }) => {
14+
return (
15+
<button
16+
onClick={() => {
17+
if (targetRef?.current) {
18+
const yOffset = -50;
19+
const y = targetRef.current.getBoundingClientRect().top + window.pageYOffset + yOffset;
20+
21+
window.scrollTo({ top: y, behavior: 'smooth' });
22+
}
23+
}}
24+
className={`cursor-pointer rounded-full text-white border-white py-2 px-8 bg-brightPink border-4 text-3xl font-bold w-48 ${classes}`}
25+
>
26+
{children}
27+
</button>
28+
);
29+
};
30+
31+
const MeetOurAmazingTeam = () => {
32+
const internalRef = useRef(null);
33+
const technicalRef = useRef(null);
34+
35+
return (
36+
<div>
37+
<div className={MEET_OUR_TEAM}>
38+
<div className={MEET_OUR_AMAZING_TEAM_TITLE}>
39+
<h1 className="text-5xl font-semibold">Meet our</h1>
40+
<Heading
41+
distanceFromTop={13}
42+
classes="italic whitespace-nowrap"
43+
underlineType={UnderlineTypes.PINK_UNDERLINE}
44+
>
45+
Amazing
46+
</Heading>
47+
<h1 className="text-5xl font-semibold ml-2"> Team</h1>
48+
</div>
49+
<div className={CONTENT_CONTAINER}>
50+
<TextSection classes="text-black pb-10 w-fit justify-center text-center mx-10 sm:mx-20 md:mx-auto lg:mx-auto">
51+
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et
52+
dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex
53+
ea commodo consequat.
54+
</TextSection>
55+
<div className="pt-5 pb-12 flex justify-center gap-6 mx-auto flex-col sm:flex-row">
56+
<Button targetRef={internalRef} timeout={500}>
57+
Internal
58+
</Button>
59+
<Button targetRef={technicalRef} timeout={1000}>
60+
Technical
61+
</Button>
62+
</div>
63+
</div>
64+
</div>
65+
66+
<section id="internal" ref={internalRef} className="h-screen p-12">
67+
<InternalTeam />
68+
</section>
69+
<section id="technical" ref={technicalRef} className="h-screen p-12 bg-[#bcfbe4]">
70+
<TechnicalTeam />
71+
</section>
72+
</div>
73+
);
74+
};
75+
76+
export default MeetOurAmazingTeam;

components/MobileNavbarDrawer.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@ const MobileNavbarDrawer = () => {
99
<a className={TEXT_CLASSES} href="who-we-are">
1010
About
1111
</a>
12+
<a className={TEXT_CLASSES} href="our-team">
13+
Our Team
14+
</a>
1215
<a className={TEXT_CLASSES} href="newsletter">
1316
News
1417
</a>

components/Navbar.jsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ const Navbar = () => {
2424
<Link href="/who-we-are" legacyBehavior>
2525
<span className={TEXT_CLASSES}>About</span>
2626
</Link>
27+
<Link href="/our-team" legacyBehavior>
28+
<span className={TEXT_CLASSES}>Our Team</span>
29+
</Link>
2730
<Link href="/newsletter" legacyBehavior>
2831
<span className={TEXT_CLASSES}>News</span>
2932
</Link>

components/Team.jsx

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import Avatar from './Avatar';
2+
3+
const Team = ({ teamMembers, teamIdentifier }) => {
4+
const TEAM_CONTAINER = 'flex flex-row flex-wrap justify-center w-full';
5+
6+
return (
7+
<div className={TEAM_CONTAINER}>
8+
{teamMembers.map((member) => (
9+
<Avatar teamIdentifier={teamIdentifier} key={member.name} {...member} />
10+
))}
11+
</div>
12+
);
13+
};
14+
15+
export default Team;

0 commit comments

Comments
 (0)