diff --git a/package-lock.json b/package-lock.json
index cfa1cf1..a1a47a5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -10,7 +10,8 @@
"dependencies": {
"next": "14.1.1",
"react": "^18",
- "react-dom": "^18"
+ "react-dom": "^18",
+ "react-icons": "^5.1.0"
},
"devDependencies": {
"@babel/preset-env": "^7.24.0",
@@ -8140,6 +8141,14 @@
"react": "^18.2.0"
}
},
+ "node_modules/react-icons": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.1.0.tgz",
+ "integrity": "sha512-D3zug1270S4hbSlIRJ0CUS97QE1yNNKDjzQe3HqY0aefp2CBn9VgzgES27sRR2gOvFK+0CNx/BW0ggOESp6fqQ==",
+ "peerDependencies": {
+ "react": "*"
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
diff --git a/package.json b/package.json
index eb570d9..9ec1ee0 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,8 @@
"dependencies": {
"next": "14.1.1",
"react": "^18",
- "react-dom": "^18"
+ "react-dom": "^18",
+ "react-icons": "^5.1.0"
},
"devDependencies": {
"@babel/preset-env": "^7.24.0",
diff --git a/src/app/components/socialSection/socialLinks.tsx b/src/app/components/socialSection/socialLinks.tsx
new file mode 100644
index 0000000..deb7ef7
--- /dev/null
+++ b/src/app/components/socialSection/socialLinks.tsx
@@ -0,0 +1,25 @@
+import { IconContext } from 'react-icons';
+import { SocialLinkData } from './socialSection';
+import styles from './socialSection.module.css';
+
+interface SocialLinksProps {
+ links: SocialLinkData[];
+}
+
+const SocialLinks = ({ links }: SocialLinksProps) => {
+ return (
+
+
+
+ );
+};
+
+export default SocialLinks;
diff --git a/src/app/components/socialSection/socialSection.module.css b/src/app/components/socialSection/socialSection.module.css
new file mode 100644
index 0000000..96da769
--- /dev/null
+++ b/src/app/components/socialSection/socialSection.module.css
@@ -0,0 +1,35 @@
+.socialSection {
+ display: flex;
+ gap: 4rem;
+ align-items: center;
+ padding: 60px 60px 60px 0;
+}
+
+.socialSection p {
+ font-family: 'Raleway', sans-serif;
+ font-size: 55px;
+}
+
+.imageContainer {
+ display: flex;
+ align-items: center;
+ justify-content: start;
+ width: 50%;
+ height: 500px;
+ background-color: #0f1034;
+ border-radius: 0 30px 30px 0;
+}
+
+.imageContainer img {
+ border-radius: 0 15px 15px 0;
+ width: 93%;
+ height: 90%;
+}
+
+.socialLinks {
+ display: flex;
+ gap: 2.5rem;
+ justify-content: space-evenly;
+ list-style: none;
+ padding: 0;
+}
diff --git a/src/app/components/socialSection/socialSection.test.js b/src/app/components/socialSection/socialSection.test.js
new file mode 100644
index 0000000..7344657
--- /dev/null
+++ b/src/app/components/socialSection/socialSection.test.js
@@ -0,0 +1,45 @@
+import { render, screen } from '@testing-library/react';
+import SocialSection from './socialSection';
+
+describe('SocialSection', () => {
+ const mockData = [
+ {
+ id: 'github',
+ imgSrc: '/assets/githubIcon.png',
+ alt: 'Github social icon',
+ link: 'https://github.com',
+ },
+ {
+ id: 'discord',
+ imgSrc: '/assets/discordIcon.png',
+ alt: 'Discord social icon',
+ link: 'https://discord.com',
+ },
+ {
+ id: 'meetup',
+ imgSrc: '/assets/meetupIcon.png',
+ alt: 'Meetup social icon',
+ link: '/',
+ },
+ {
+ id: 'linkedin',
+ imgSrc: '/assets/linkedinIcon.png',
+ alt: 'LinkedIn social icon',
+ link: '/',
+ },
+ ];
+
+ test('renders SocialSection component', () => {
+ render();
+
+ const socialSection = screen.getByTestId('socialSection');
+ expect(socialSection).toBeInTheDocument();
+ });
+
+ test('renders all social icons', () => {
+ render();
+
+ const linkList = screen.getAllByRole('listitem');
+ expect(linkList).toHaveLength(4);
+ });
+});
diff --git a/src/app/components/socialSection/socialSection.tsx b/src/app/components/socialSection/socialSection.tsx
new file mode 100644
index 0000000..8044ccf
--- /dev/null
+++ b/src/app/components/socialSection/socialSection.tsx
@@ -0,0 +1,40 @@
+import Image from 'next/image';
+import SocialLinks from './socialLinks';
+import styles from './socialSection.module.css';
+
+export interface SocialLinkData {
+ id: string;
+ icon: React.ReactNode;
+ imgSrc: string;
+ alt: string;
+ link: string;
+}
+
+interface SocialSectionProps {
+ socialData: SocialLinkData[];
+}
+
+export default function SocialSection({ socialData }: SocialSectionProps) {
+ return (
+
+
+
+
+
+
+ Join our Discord and
other social links!
+
+
+ This is YOUR community,
+
be a part of it!
+
+
+
+
+ );
+}
diff --git a/src/app/hooks/useMediaQuery/README.md b/src/app/hooks/useMediaQuery/README.md
new file mode 100644
index 0000000..45df5f3
--- /dev/null
+++ b/src/app/hooks/useMediaQuery/README.md
@@ -0,0 +1,7 @@
+This is a slimmer version of the `useMediaQuery` hook from [useHooks-ts](https://usehooks-ts.com/react-hook/use-media-query)
+
+This hook uses the [`matchMedia()`](https://developer.mozilla.org/en-US/docs/Web/API/Window/matchMedia) method of the `Window` object to check for matching conditions against a media query passed into the hook.
+
+`useMediaQuery` takes a media query argument passed as a string:
+
+`useMediaQuery('(max-width: 750px)')`
diff --git a/src/app/hooks/useMediaQuery/index.tsx b/src/app/hooks/useMediaQuery/index.tsx
new file mode 100644
index 0000000..a3b27f4
--- /dev/null
+++ b/src/app/hooks/useMediaQuery/index.tsx
@@ -0,0 +1,18 @@
+import { useState, useEffect } from 'react';
+
+const useMediaQuery = (query: string): boolean => {
+ const [isMatch, setIsMatch] = useState(false);
+
+ useEffect(() => {
+ const mediaQueryList = window.matchMedia(query);
+ setIsMatch(mediaQueryList.matches);
+
+ mediaQueryList.onchange = (event) => {
+ setIsMatch(event.matches);
+ };
+ }, [query]);
+
+ return isMatch;
+};
+
+export default useMediaQuery;
diff --git a/src/app/page.tsx b/src/app/page.tsx
index 4961c35..1db7719 100644
--- a/src/app/page.tsx
+++ b/src/app/page.tsx
@@ -1,7 +1,11 @@
+'use client';
+import { FaDiscord, FaGithub, FaLinkedin, FaMeetup } from 'react-icons/fa';
+import useMediaQuery from './hooks/useMediaQuery';
import CardsSection from './components/cardsSection/cardsSection';
import BannerSection from './components/bannerSection/bannerSection';
import HeroSection from './components/heroSection/heroSection';
import Navbar from './components/navbar/navbar';
+import SocialSection from './components/socialSection/socialSection';
import styles from './page.module.css';
import GroupPhotoSection from './components/groupPhotoSection/groupPhotoSection';
import BentoSection from './components/bentoSection/bentoSection';
@@ -35,14 +39,51 @@ export default function Home() {
meetupUrl: 'https://www.meetup.com/dallas-software-developers-meetup/',
communityUrl: '/',
cohortUrl: '/',
+ githubUrl: 'https://github.com/dallassoftwaredevelopers',
+ discordUrl: '/',
+ linkedinUrl: 'https://www.linkedin.com/company/dallas-software-developers',
};
+ const socialData = [
+ {
+ id: 'github',
+ icon: ,
+ imgSrc: '/assets/githubIcon.png',
+ alt: 'Github social icon',
+ link: labelMap.githubUrl,
+ },
+ {
+ id: 'discord',
+ icon: ,
+ imgSrc: '/assets/discordIcon.png',
+ alt: 'Discord social icon',
+ link: labelMap.discordUrl,
+ },
+ {
+ id: 'meetup',
+ icon: ,
+ imgSrc: '/assets/meetupIcon.png',
+ alt: 'Meetup social icon',
+ link: labelMap.meetupUrl,
+ },
+ {
+ id: 'linkedin',
+ icon: ,
+ imgSrc: '/assets/linkedinIcon.png',
+ alt: 'LinkedIn social icon',
+ link: labelMap.linkedinUrl,
+ },
+ ];
+
+ const isDesktop = useMediaQuery('(min-width: 1024px)');
+
return (
+ {isDesktop && }