From c1fac48ff97f388b69bf7e7bb31e1c0409532da3 Mon Sep 17 00:00:00 2001 From: CarmenHe <43501759+CarmenHe@users.noreply.github.com> Date: Fri, 25 Aug 2023 12:24:49 -0700 Subject: [PATCH 1/5] shows default image for board without photo link --- src/api/BoardAPI.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/BoardAPI.ts b/src/api/BoardAPI.ts index 563a054..a8b032f 100644 --- a/src/api/BoardAPI.ts +++ b/src/api/BoardAPI.ts @@ -13,6 +13,9 @@ const formatLinkedIn = (val: string): string => { return val.includes("https://www.linkedin.com/in/") ? val : `https://www.linkedin.com/in/${val}`; }; + +//If data from row is blank or not formatted correctly (jpg or jpeg), use default link in place, otherwise do nothing +const formatProfileImage = (val: string) => ((val?.includes(".jpg") || false) || (val?.includes(".jpeg")|| false) || (val?.includes(".png")||false)) ? val : `https://i.imgur.com/j7icEAQ.png`; export const getBoardData = async () => { const { BOARD_SPREADSHEET_ID, GOOGLE_SERVICE_ACC_EMAIL, GOOGLE_SERVICE_KEY_PRIVATE } = process.env; @@ -43,7 +46,7 @@ export const getBoardData = async () => { name: row["Name"], org: row["Team"]?.toLowerCase(), title: row["Position"], - profile_image: row["Profile Picture"], + profile_image: formatProfileImage(row["Profile Picture"]), email: row["ACM Email"] || null, personal_link: row["Website"] || null, linkedin_link: formatLinkedIn(row["LinkedIn"] || null), From 7db2e149b11df99cd28e0048a33c128d825e7b54 Mon Sep 17 00:00:00 2001 From: CarmenHe <43501759+CarmenHe@users.noreply.github.com> Date: Fri, 25 Aug 2023 12:28:28 -0700 Subject: [PATCH 2/5] checks board photo links, shows default photo --- src/api/BoardAPI.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/BoardAPI.ts b/src/api/BoardAPI.ts index a8b032f..7ebfe53 100644 --- a/src/api/BoardAPI.ts +++ b/src/api/BoardAPI.ts @@ -16,6 +16,7 @@ const formatLinkedIn = (val: string): string => { //If data from row is blank or not formatted correctly (jpg or jpeg), use default link in place, otherwise do nothing const formatProfileImage = (val: string) => ((val?.includes(".jpg") || false) || (val?.includes(".jpeg")|| false) || (val?.includes(".png")||false)) ? val : `https://i.imgur.com/j7icEAQ.png`; + export const getBoardData = async () => { const { BOARD_SPREADSHEET_ID, GOOGLE_SERVICE_ACC_EMAIL, GOOGLE_SERVICE_KEY_PRIVATE } = process.env; From ef2e2eafebbc551dc2677f6a85d85ac0d80eb2d0 Mon Sep 17 00:00:00 2001 From: CarmenHe <43501759+CarmenHe@users.noreply.github.com> Date: Mon, 23 Oct 2023 19:10:53 -0700 Subject: [PATCH 3/5] Sized down default image to fit container --- src/api/BoardAPI.ts | 2 +- src/components/BoardCard/index.tsx | 3 ++- src/components/BoardCard/styles.module.scss | 6 ++++++ src/components/BoardCard/styles.module.scss.d.ts | 1 + 4 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/api/BoardAPI.ts b/src/api/BoardAPI.ts index 7ebfe53..3890073 100644 --- a/src/api/BoardAPI.ts +++ b/src/api/BoardAPI.ts @@ -15,7 +15,7 @@ const formatLinkedIn = (val: string): string => { //If data from row is blank or not formatted correctly (jpg or jpeg), use default link in place, otherwise do nothing -const formatProfileImage = (val: string) => ((val?.includes(".jpg") || false) || (val?.includes(".jpeg")|| false) || (val?.includes(".png")||false)) ? val : `https://i.imgur.com/j7icEAQ.png`; +const formatProfileImage = (val: string) => ((val?.includes(".jpg") || false) || (val?.includes(".jpeg")|| false) || (val?.includes(".png")||false)) ? val : `https://i.imgur.com/WneyVtE.png`; export const getBoardData = async () => { const { BOARD_SPREADSHEET_ID, GOOGLE_SERVICE_ACC_EMAIL, GOOGLE_SERVICE_KEY_PRIVATE } = diff --git a/src/components/BoardCard/index.tsx b/src/components/BoardCard/index.tsx index 1523ee2..5bb68e1 100644 --- a/src/components/BoardCard/index.tsx +++ b/src/components/BoardCard/index.tsx @@ -30,12 +30,13 @@ const BoardCard: React.FC = ({ boardmember }) => { const portfolioLink = withHttp(personal_link); const linkedinLink = withHttp(linkedin_link); + const defaultImage = (profile_image) => (profile_image==="https://i.imgur.com/WneyVtE.png") ? style.default: null; return (
{title}
- +

{name}

diff --git a/src/components/BoardCard/styles.module.scss b/src/components/BoardCard/styles.module.scss index 13c7bfc..a373e78 100644 --- a/src/components/BoardCard/styles.module.scss +++ b/src/components/BoardCard/styles.module.scss @@ -48,6 +48,12 @@ padding: 0; margin: 0; } + .default{ + object-fit: contain; + top: 0; + min-height:100%; + height: 100%; + } } .footer { width: 100%; diff --git a/src/components/BoardCard/styles.module.scss.d.ts b/src/components/BoardCard/styles.module.scss.d.ts index 096f900..4616cf2 100644 --- a/src/components/BoardCard/styles.module.scss.d.ts +++ b/src/components/BoardCard/styles.module.scss.d.ts @@ -5,6 +5,7 @@ declare namespace StylesModuleScssNamespace { ai: string; card: string; cyber: string; + default: string; footer: string; image: string; links: string; From ca9cb0427d8bfbb743fe710d43012c4a8a0daad5 Mon Sep 17 00:00:00 2001 From: CarmenHe <43501759+CarmenHe@users.noreply.github.com> Date: Mon, 27 Nov 2023 19:32:24 -0800 Subject: [PATCH 4/5] improved code concision, access images from codebase --- src/api/BoardAPI.ts | 26 ++++++++++----------- src/components/BoardCard/index.tsx | 23 ++++++++++++++---- src/components/BoardCard/styles.module.scss | 4 ++-- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/api/BoardAPI.ts b/src/api/BoardAPI.ts index 3890073..2a78089 100644 --- a/src/api/BoardAPI.ts +++ b/src/api/BoardAPI.ts @@ -10,16 +10,17 @@ import { // Otherwise, consistently format as a LinkedIn profile url (some people may provide only the username portion on the spreadsheet) const formatLinkedIn = (val: string): string => { if (!val) return null; - return val.includes("https://www.linkedin.com/in/") ? val : `https://www.linkedin.com/in/${val}`; + return val.includes("https://www.linkedin.com/in/") + ? val + : `https://www.linkedin.com/in/${val}`; }; - -//If data from row is blank or not formatted correctly (jpg or jpeg), use default link in place, otherwise do nothing -const formatProfileImage = (val: string) => ((val?.includes(".jpg") || false) || (val?.includes(".jpeg")|| false) || (val?.includes(".png")||false)) ? val : `https://i.imgur.com/WneyVtE.png`; - export const getBoardData = async () => { - const { BOARD_SPREADSHEET_ID, GOOGLE_SERVICE_ACC_EMAIL, GOOGLE_SERVICE_KEY_PRIVATE } = - process.env; + const { + BOARD_SPREADSHEET_ID, + GOOGLE_SERVICE_ACC_EMAIL, + GOOGLE_SERVICE_KEY_PRIVATE, + } = process.env; const doc = new GoogleSpreadsheet(BOARD_SPREADSHEET_ID); @@ -42,22 +43,21 @@ export const getBoardData = async () => { // Map through array of rows, each one is an object with column headers as keys const boardMembers = rows - .map(row => { + .map((row) => { const boardMemberData: BoardMemberProps = { name: row["Name"], org: row["Team"]?.toLowerCase(), title: row["Position"], - profile_image: formatProfileImage(row["Profile Picture"]), + profile_image: row["Profile Picture"] || "", email: row["ACM Email"] || null, personal_link: row["Website"] || null, linkedin_link: formatLinkedIn(row["LinkedIn"] || null), }; return boardMemberData; }) - .filter(user => user.name) // name is required - .filter(user => user.org && user.org !== "members at large") // valid suborg is required - .filter(user => user.title) // position title is required - .filter(user => user.profile_image); // image url is required + .filter((user) => user.name) // name is required + .filter((user) => user.org && user.org !== "members at large") // valid suborg is required + .filter((user) => user.title); // position title is required return boardMembers; }; diff --git a/src/components/BoardCard/index.tsx b/src/components/BoardCard/index.tsx index 5bb68e1..b22b39b 100644 --- a/src/components/BoardCard/index.tsx +++ b/src/components/BoardCard/index.tsx @@ -2,6 +2,7 @@ import style from "./styles.module.scss"; import GeneralDefault from "public/assets/default-board-images/general-default.svg"; import AIDefault from "public/assets/default-board-images/ai-default.svg"; import CyberDefault from "public/assets/default-board-images/cyber-default.svg"; +import HackDefault from "public/assets/default-board-images/hack-default.svg"; import { BoardMemberProps } from "src/types/index"; import { withHttp } from "src/utils/general"; @@ -9,7 +10,6 @@ interface BoardCardProps { boardmember: BoardMemberProps; } - const BoardCard: React.FC = ({ boardmember }) => { const { name = "", @@ -25,24 +25,39 @@ const BoardCard: React.FC = ({ boardmember }) => { general: GeneralDefault, ai: AIDefault, cyber: CyberDefault, + hack: HackDefault, }; + const boardPictureRegex = /(jpg)|(png)|(jpeg)/gim; + const validProfileImage = profile_image.match(boardPictureRegex); + + let profileImage = profile_image; + if (!validProfileImage) { + profileImage = defaultImgs[org]?.src ?? defaultImgs.general.src; + } const portfolioLink = withHttp(personal_link); const linkedinLink = withHttp(linkedin_link); - const defaultImage = (profile_image) => (profile_image==="https://i.imgur.com/WneyVtE.png") ? style.default: null; return (
{title}
- + Board Photo

{name}

{!email ? null : ( - + diff --git a/src/components/BoardCard/styles.module.scss b/src/components/BoardCard/styles.module.scss index a373e78..fc27929 100644 --- a/src/components/BoardCard/styles.module.scss +++ b/src/components/BoardCard/styles.module.scss @@ -48,10 +48,10 @@ padding: 0; margin: 0; } - .default{ + .default { object-fit: contain; top: 0; - min-height:100%; + min-height: 100%; height: 100%; } } From 5965dfa69881e0e53eccf67bd2adfaa102ffff19 Mon Sep 17 00:00:00 2001 From: CarmenHe <43501759+CarmenHe@users.noreply.github.com> Date: Mon, 29 Jan 2024 18:52:31 -0800 Subject: [PATCH 5/5] Button on events card opens dialog with share options --- src/components/EventCard/index.tsx | 18 ++++++-- .../ShareToModal/ShareToModal.module.scss | 0 src/components/ShareToModal/index.tsx | 42 +++++++++++++++++++ 3 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 src/components/ShareToModal/ShareToModal.module.scss create mode 100644 src/components/ShareToModal/index.tsx diff --git a/src/components/EventCard/index.tsx b/src/components/EventCard/index.tsx index 4dffecb..91382ec 100644 --- a/src/components/EventCard/index.tsx +++ b/src/components/EventCard/index.tsx @@ -2,15 +2,18 @@ import Link from "next/link"; import { saveToAppleCal, EventObject, saveToGoogleCal } from "src/api/EventsAPI"; import { useState } from "react"; import { CalendarModal } from "../CalendarModal"; +import { ShareToModal } from "../ShareToModal"; import s from "./EventCard.module.scss"; import { days, months, formatURLEventTitle, getDateTime, withHttp } from "src/utils/general"; import { FaCalendarAlt } from "react-icons/fa"; +import { FaShareAlt } from "react-icons/fa"; import { GRAY } from "src/utils/constants"; const EventCard: React.FC<{ event: EventObject; }> = ({ event }) => { - const [isModalOpen, setIsModalOpen] = useState(false); + const [isCalModalOpen, setIsCalModalOpen] = useState(false); + const [isShareModalOpen, setIsShareModalOpen] = useState(false); const month = months[new Date(event.start).getMonth()]; const date = new Date(event.start).getDate(); const day = days[new Date(event.start).getDay()]; @@ -18,7 +21,8 @@ const EventCard: React.FC<{ const { committee, uuid, title, location, eventLink } = event; return ( <> - setIsModalOpen(false)} event={event} /> + setIsCalModalOpen(false)} event={event} /> + setIsShareModalOpen(false)} event={event} />
diff --git a/src/components/ShareToModal/ShareToModal.module.scss b/src/components/ShareToModal/ShareToModal.module.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/components/ShareToModal/index.tsx b/src/components/ShareToModal/index.tsx new file mode 100644 index 0000000..39f15c0 --- /dev/null +++ b/src/components/ShareToModal/index.tsx @@ -0,0 +1,42 @@ +import React from "react"; +import { + EmailShareButton, + EmailIcon, + FacebookShareButton, + FacebookIcon, + LinkedinShareButton, + LinkedinIcon + } from 'next-share'; +import { EventObject } from "src/api/EventsAPI"; + +interface ShareToModalProps{ + show: boolean; + event: EventObject; + onClose: () => void; +} + +export const ShareToModal:React.FC = ({ show, event, onClose }) => ( + +
+

Share Event with Friends

+
+ + + Email + + + + Facebook + +
+
+ +
+
+);