From e6c996f149b659fd41fc4c8f9147a762958590dd Mon Sep 17 00:00:00 2001 From: prasanth Date: Fri, 13 Dec 2024 12:36:08 +0530 Subject: [PATCH 1/2] feat: team and member details irl contributions --- analytics/members.analytics.ts | 18 +- analytics/teams.analytics.ts | 18 +- app/members/[id]/page.module.css | 9 +- app/members/[id]/page.tsx | 6 + app/teams/[id]/page.module.css | 7 + app/teams/[id]/page.tsx | 7 + .../member-irl-contributions.tsx | 466 ++++++++++++++++++ .../team-details/team-irl-contributions.tsx | 452 +++++++++++++++++ package-lock.json | 7 + package.json | 1 + public/icons/attendee_icon.svg | 12 + public/icons/host_icon.svg | 16 + public/icons/speaker_icon.svg | 11 + services/members.service.ts | 5 +- services/teams.service.ts | 1 + types/members.types.ts | 1 + types/teams.types.ts | 1 + utils/constants.ts | 4 + utils/member.utils.ts | 32 ++ utils/team.utils.ts | 30 ++ 20 files changed, 1099 insertions(+), 5 deletions(-) create mode 100644 components/page/member-details/member-irl-contributions.tsx create mode 100644 components/page/team-details/team-irl-contributions.tsx create mode 100644 public/icons/attendee_icon.svg create mode 100644 public/icons/host_icon.svg create mode 100644 public/icons/speaker_icon.svg diff --git a/analytics/members.analytics.ts b/analytics/members.analytics.ts index 47ac4006..4157736c 100644 --- a/analytics/members.analytics.ts +++ b/analytics/members.analytics.ts @@ -315,6 +315,20 @@ export const useMemberAnalytics = () => { captureEvent(MEMBER_ANALYTICS_EVENTS.MEMBER_DETAIL_BIO_EDIT_RECORD_SAVE, params); } + function onClickSeeMoreIrlContribution(user: IAnalyticsUserInfo | null){ + const params = { + user, + }; + captureEvent(MEMBER_ANALYTICS_EVENTS.ON_CLICK_SEE_MORE_BUTTON_IRL_CONTRIBUTIONS, params); + } + + function onClickEventIrlContribution(user: IAnalyticsUserInfo | null){ + const params = { + user, + }; + captureEvent(MEMBER_ANALYTICS_EVENTS.MEMBER_DETAILS_ON_CLICK_IRL_CONTRIBUTIONS, params); + } + return { onOfficeHourClicked, onProjectContributionEditClicked, @@ -349,6 +363,8 @@ export const useMemberAnalytics = () => { onMemberDetailsBioEditClicked, onMemberDetailsBioEditSaveClicked, onMemberDetailsBioEditCancelClicked, - recordBioSave + recordBioSave, + onClickSeeMoreIrlContribution, + onClickEventIrlContribution, }; }; diff --git a/analytics/teams.analytics.ts b/analytics/teams.analytics.ts index c92160d8..d33199d3 100644 --- a/analytics/teams.analytics.ts +++ b/analytics/teams.analytics.ts @@ -256,6 +256,20 @@ export const useTeamAnalytics = () => { captureEvent(TEAMS_ANALYTICS_EVENTS.TEAM_DETAIL_ABOUT_SAVE, params); } + function onClickSeeMoreIrlContribution(user: IAnalyticsUserInfo | null){ + const params = { + user, + }; + captureEvent(TEAMS_ANALYTICS_EVENTS.ON_CLICK_SEE_MORE_BUTTON_IRL_CONTRIBUTIONS, params); + } + + function onClickTeamIrlContribution(user: IAnalyticsUserInfo | null){ + const params = { + user, + }; + captureEvent(TEAMS_ANALYTICS_EVENTS. TEAM_DETAILS_ON_CLICK_IRL_CONTRIBUTIONS, params); + } + return { onOfficeHoursSelected, onFriendsOfProtocolSelected, @@ -287,7 +301,9 @@ export const useTeamAnalytics = () => { onTeamDetailAboutEditSaveClicked, onTeamDetailAboutEditCancelClicked, onTeamDetailAboutEditClicked, - recordAboutSave + recordAboutSave, + onClickSeeMoreIrlContribution, + onClickTeamIrlContribution } } \ No newline at end of file diff --git a/app/members/[id]/page.module.css b/app/members/[id]/page.module.css index 162b197a..2ae78c70 100644 --- a/app/members/[id]/page.module.css +++ b/app/members/[id]/page.module.css @@ -60,6 +60,13 @@ background: #fff; } +.memberDetail__irlContribution{ + box-shadow: 0px 4px 4px 0px #0f172a0a; + background: #fff; + min-height: 20px; + padding: 20px; +} + @media (min-width: 1024px) { .memberDetail { align-items: center; @@ -86,7 +93,7 @@ border-radius: 8px; } - .memberDetail__container__repositories { + .memberDetail__container__repositories, .memberDetail__irlContribution { border-radius: 8px; } } \ No newline at end of file diff --git a/app/members/[id]/page.tsx b/app/members/[id]/page.tsx index b7a535cb..0c339efc 100644 --- a/app/members/[id]/page.tsx +++ b/app/members/[id]/page.tsx @@ -14,6 +14,7 @@ import { getAllTeams } from '@/services/teams.service'; import MemberProjectContribution from '@/components/page/member-details/member-project-contribution'; import MemberOfficeHours from '@/components/page/member-details/member-office-hours'; import Bio from '@/components/page/member-details/bio'; +import IrlMemberContribution from '@/components/page/member-details/member-irl-contributions'; const MemberDetails = async ({ params }: { params: any }) => { const memberId = params?.id; @@ -52,6 +53,11 @@ const MemberDetails = async ({ params }: { params: any }) => { )} + {member.eventGuests.length > 0 && ( +
+ +
+ )} {isLoggedIn && (
diff --git a/app/teams/[id]/page.module.css b/app/teams/[id]/page.module.css index 2c125d19..778964eb 100644 --- a/app/teams/[id]/page.module.css +++ b/app/teams/[id]/page.module.css @@ -47,6 +47,13 @@ min-height: 100px; } +.teamDetail__irlContributions { + box-shadow: 0px 4px 4px 0px #0f172a0a; + background: #fff; + min-height: 20px; + padding: 20px; +} + @media (min-width: 1024px) { .teamDetail { align-items: center; diff --git a/app/teams/[id]/page.tsx b/app/teams/[id]/page.tsx index 704f353b..ae585e8b 100644 --- a/app/teams/[id]/page.tsx +++ b/app/teams/[id]/page.tsx @@ -19,6 +19,7 @@ import { getFocusAreas } from '@/services/common.service'; import { IFocusArea } from '@/types/shared.types'; import SelectedFocusAreas from '@/components/core/selected-focus-area'; import TeamOfficeHours from '@/components/page/team-details/team-office-hours'; +import TeamIrlContributions from '@/components/page/team-details/team-irl-contributions'; async function Page({ params }: { params: ITeamDetailParams }) { const teamId: string = params?.id; @@ -60,6 +61,12 @@ async function Page({ params }: { params: ITeamDetailParams }) {
)} + {/* Irl Contribuions */} + {team.eventGuests.length > 0 && +
+ +
+ } {/* Member */}
diff --git a/components/page/member-details/member-irl-contributions.tsx b/components/page/member-details/member-irl-contributions.tsx new file mode 100644 index 00000000..367c49b5 --- /dev/null +++ b/components/page/member-details/member-irl-contributions.tsx @@ -0,0 +1,466 @@ +'use client'; + +import { Fragment, useRef, useState } from 'react'; +import Modal from '@/components/core/modal'; +import { IMember } from '@/types/members.types'; +import { IAnalyticsUserInfo, IUserInfo } from '@/types/shared.types'; +import { useMemberAnalytics } from '@/analytics/members.analytics'; +import React from 'react'; +import { getFormattedDateString } from '@/utils/member.utils'; +import { Tooltip } from '@/components/core/tooltip/tooltip'; +import { usePathname, useRouter } from 'next/navigation'; +import { toZonedTime } from 'date-fns-tz'; + +interface IEvent { + uid: string; + name: string; + type: string | null; + slugURL: string; + startDate: string; + endDate: string; + location: any; +} + +interface IEventGuest { + uid: string; + isHost: boolean; + isSpeaker: boolean; + event: IEvent; +} + +interface GroupedEvents { + Attendee: IEvent[]; + Speaker: IEvent[]; + Host: IEvent[]; +} + +interface IMemberRepositories { + member: IMember; + userInfo: IAnalyticsUserInfo; +} + +const IrlMemberContribution = (props: IMemberRepositories) => { + const userInfo = props?.userInfo; + const modalRef = useRef(null); + const [selectedRole, setSelectedRole] = useState(''); + const analytics = useMemberAnalytics(); + const router = useRouter(); + + const member = props?.member?.eventGuests; + const transformData = (array: IEventGuest[]): GroupedEvents => { + return array.reduce( + (acc: GroupedEvents, item) => { + if ((!item.isSpeaker && !item.isHost)) { + acc.Attendee.push(item.event); + } + + if (item.isSpeaker) acc.Speaker.push(item.event); + if (item.isHost) acc.Host.push(item.event); + + return acc; + }, + { Attendee: [], Speaker: [], Host: [] } + ); + }; + + const groupedData: GroupedEvents = member ? transformData(member) : { Attendee: [], Speaker: [], Host: [] }; + + const onClose = () => { + if (modalRef.current) { + modalRef.current.close(); + } + }; + + const onClickHandler = (role: string) => { + if (modalRef.current) { + setSelectedRole(role); + modalRef.current.showModal(); + } + analytics.onClickSeeMoreIrlContribution(userInfo); + }; + + const handleEventClick = (details: any, role: any) => { + analytics.onClickEventIrlContribution(userInfo); + // const isActive = new Date(details?.endDate) > new Date(); + const isActive = checkTimeZone(details) + + const type = isActive ? "upcoming" : "past"; + const location = details.location.location ?? ""; + const baseUrl = window.location.origin; + let url = `irl?location=${location}&type=${type}`; + + if (role === "Attendee" && type === "upcoming") { + url += `&attending=${details.name}`; + } + + if (type === "past") { + url += `&event=${details.slugURL}`; + } + + const fullUrl = `${baseUrl}/${url}`; + window.open(fullUrl, '_blank'); + } + + + const checkTimeZone = (details: any) => { + const timezone = details?.location?.timezone; + const endDateInTargetTimezone = toZonedTime(new Date(details?.endDate), timezone); + const currentDateInTargetTimezone = toZonedTime(new Date(), timezone); + + return endDateInTargetTimezone.getTime() > currentDateInTargetTimezone.getTime(); + } + + return ( + <> +
+
IRL Contributions
+
+ {Object.entries(groupedData).map(([role, events]) => { + if (events.length === 0) return null; + const visibleEvents = events?.slice(0, 5); + const additionalCount = events?.length - visibleEvents?.length; + + return ( +
+
+ {role.toLowerCase()} + {role} +
+
+ {visibleEvents.map((details: { name: any; startDate: any; endDate: any }, index: React.Key | null | undefined) => { + const isActive = checkTimeZone(details); + return ( +
{ handleEventClick(details, role) }} + > + + {details?.name} +
+ } + trigger={ +
{details?.name}
+ } + /> +
+ {getFormattedDateString(details?.startDate, details?.endDate)} +
+
+ ); + })} + {additionalCount > 0 && ( +
onClickHandler(role)} + > + +{additionalCount} +
+ )} +
+
+ ); + })} +
+
+ + +
+ {Object.entries(groupedData) + .filter(([role]) => role === selectedRole) + .map(([role, events]) => ( + <> +
+
{role}
+
+
+ {events.map((resource: { link: any; name: any; }, index: React.Key | null | undefined) => ( +
+
{resource?.name}
+
+ arrow icon +
+
+ ))} +
+ + ))} + + +
+
+ + + ); +}; + +export default IrlMemberContribution; diff --git a/components/page/team-details/team-irl-contributions.tsx b/components/page/team-details/team-irl-contributions.tsx new file mode 100644 index 00000000..561cbe77 --- /dev/null +++ b/components/page/team-details/team-irl-contributions.tsx @@ -0,0 +1,452 @@ +'use client'; + +import { Fragment, useRef, useState } from 'react'; +import Modal from '@/components/core/modal'; +import { IMember } from '@/types/members.types'; +import { IAnalyticsUserInfo, IUserInfo } from '@/types/shared.types'; +import React from 'react'; +import { getFormattedDateString } from '@/utils/member.utils'; +import { Tooltip } from '@/components/core/tooltip/tooltip'; +import { ITeam } from '@/types/teams.types'; +import { useTeamAnalytics } from '@/analytics/teams.analytics'; +import { toZonedTime } from 'date-fns-tz'; + +interface IEvent { + uid: string; + name: string; + type: string | null; + slugURL: string; + startDate: string; + endDate: string; + location: any; +} + +interface IEventGuest { + uid: string; + isHost: boolean; + event: IEvent; +} + +interface GroupedEvents { + Host: IEvent[]; +} + +interface ITeamMembers { + members: IMember[] | undefined; + teamId: string; + team: ITeam | undefined; + userInfo: IAnalyticsUserInfo ; + } + +const TeamIrlContributions = (props: ITeamMembers) => { + const userInfo = props?.userInfo; + const modalRef = useRef(null); + const [selectedRole, setSelectedRole] = useState(''); + const analytics = useTeamAnalytics(); + + const team = props?.team?.eventGuests; + const transformData = (event: IEventGuest[]): GroupedEvents => { + return event.reduce( + (acc: GroupedEvents, item) => { + acc.Host.push(item.event); + return acc; + }, + { Host: [] } + ); + }; + + const groupedData: GroupedEvents = team ? transformData(team) : {Host: [] }; + + const onClose = () => { + if (modalRef.current) { + modalRef.current.close(); + } + }; + + const onClickHandler = (role: string) => { + if (modalRef.current) { + setSelectedRole(role); + modalRef.current.showModal(); + } + analytics.onClickSeeMoreIrlContribution(userInfo); + }; + + const handleEventClick = (details: any, role: any) => { + analytics.onClickTeamIrlContribution(userInfo); + // const isActive = new Date(details?.endDate) > new Date(); + const isActive = checkTimeZone(details) + + const type = isActive ? "upcoming" : "past"; + const location = details.location.location ?? ""; + const baseUrl = window.location.origin; + let url = `irl?location=${location}&type=${type}`; + + if (type === "past") { + url += `&event=${details.slugURL}`; + } + + const fullUrl = `${baseUrl}/${url}`; + window.open(fullUrl, '_blank'); + } + + + const checkTimeZone = (details: any) => { + const timezone = details?.location?.timezone; + const endDateInTargetTimezone = toZonedTime(new Date(details?.endDate), timezone); + const currentDateInTargetTimezone = toZonedTime(new Date(), timezone); + + return endDateInTargetTimezone.getTime() > currentDateInTargetTimezone.getTime(); + } + return ( + <> +
+
IRL Contributions
+
+ {Object.entries(groupedData).map(([role, events]) => { + const visibleEvents = events?.slice(0, 5); + const additionalCount = events?.length - visibleEvents?.length; + + return ( +
+
+ {role.toLowerCase()} + {role} +
+
+ {visibleEvents.map((details: { name: any; startDate: any; endDate: any }, index: React.Key | null | undefined) => { + const isActive = checkTimeZone(details); + return ( +
{handleEventClick(details, role)}} + > + + {details?.name} +
+ } + trigger={ +
{details?.name}
+ } + /> +
+ {getFormattedDateString(details?.startDate, details?.endDate)} +
+
+ ); + })} + {additionalCount > 0 && ( +
onClickHandler(role)} + > + +{additionalCount} +
+ )} +
+
+ ); + })} +
+ + + +
+ {Object.entries(groupedData) + .filter(([role]) => role === selectedRole) + .map(([role, events]) => ( + <> +
+
{role}
+
+
+ {events.map((resource: { link: any; name: any; }, index: React.Key | null | undefined) => ( +
+
{resource?.name}
+
+ arrow icon +
+
+ ))} +
+ + ))} + + +
+
+ + + ); +}; + +export default TeamIrlContributions; diff --git a/package-lock.json b/package-lock.json index 2c7abbb6..edc27051 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@radix-ui/react-tooltip": "^1.0.7", "@testing-library/user-event": "^14.5.2", "@tinymce/tinymce-react": "^5.1.1", + "date-fns-tz": "^3.2.0", "embla-carousel-react": "^8.1.8", "isomorphic-dompurify": "^2.13.0", "js-cookie": "^3.0.5", @@ -6350,6 +6351,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns-tz": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-3.2.0.tgz", + "integrity": "sha512-sg8HqoTEulcbbbVXeg84u5UnlsQa8GS5QXMqjjYIhS4abEVVKIUwe0/l/UhrZdKaL/W5eWZNlbTeEIiOXTcsBQ==", + "license": "MIT" + }, "node_modules/dateformat": { "version": "4.6.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", diff --git a/package.json b/package.json index 3a1fd5ef..a764ebb7 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@radix-ui/react-tooltip": "^1.0.7", "@testing-library/user-event": "^14.5.2", "@tinymce/tinymce-react": "^5.1.1", + "date-fns-tz": "^3.2.0", "embla-carousel-react": "^8.1.8", "isomorphic-dompurify": "^2.13.0", "js-cookie": "^3.0.5", diff --git a/public/icons/attendee_icon.svg b/public/icons/attendee_icon.svg new file mode 100644 index 00000000..1f2c1c6b --- /dev/null +++ b/public/icons/attendee_icon.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/icons/host_icon.svg b/public/icons/host_icon.svg new file mode 100644 index 00000000..97a673cd --- /dev/null +++ b/public/icons/host_icon.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/public/icons/speaker_icon.svg b/public/icons/speaker_icon.svg new file mode 100644 index 00000000..037850fc --- /dev/null +++ b/public/icons/speaker_icon.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/services/members.service.ts b/services/members.service.ts index e7bd3356..31448ef5 100644 --- a/services/members.service.ts +++ b/services/members.service.ts @@ -132,7 +132,8 @@ export const getMember = async (id: string, query: any, isLoggedIn?: boolean, us teamAndRoles: teamAndRoles, preferences: result.preferences ?? null, isSubscribedToNewsletter: result?.isSubscribedToNewsletter ?? false, - isVerified: result?.isVerified + isVerified: result?.isVerified, + eventGuests: result?.eventGuests ?? [], }; if (isLoggedIn) { @@ -305,7 +306,7 @@ export const getMemberInfo = async (memberUid: string) => { } }) - const formatted = { ...result, imageUrl: result?.image?.url, moreDetails: result.moreDetails ?? '', openToWork: result.openToWork ?? false, officeHours: result.officeHours ?? '', projectContributions: projectContributions, teamMemberRoles: teamMemberRoles, skills: skills }; + const formatted = { ...result, imageUrl: result?.image?.url, moreDetails: result.moreDetails ?? '', openToWork: result.openToWork ?? false, officeHours: result.officeHours ?? '', projectContributions: projectContributions, teamMemberRoles: teamMemberRoles, skills: skills}; return { data: formatted }; }; diff --git a/services/teams.service.ts b/services/teams.service.ts index 8b5fdba4..f2decec5 100644 --- a/services/teams.service.ts +++ b/services/teams.service.ts @@ -116,6 +116,7 @@ export const getTeam = async (id: string, options: string | string[][] | Record< contributingProjects: result?.contributingProjects, officeHours: result?.officeHours, teamFocusAreas: result?.teamFocusAreas, + eventGuests: result?.eventGuests, }; return { data: { formatedData } }; }; diff --git a/types/members.types.ts b/types/members.types.ts index 0486768d..8b5e2250 100644 --- a/types/members.types.ts +++ b/types/members.types.ts @@ -62,6 +62,7 @@ export interface IMember { preferences: IMemberPreferences; bio?: string; isVerified?: boolean; + eventGuests?: []; } export interface ILoggedoutMember {} diff --git a/types/teams.types.ts b/types/teams.types.ts index a7448a48..fe687ea2 100644 --- a/types/teams.types.ts +++ b/types/teams.types.ts @@ -80,6 +80,7 @@ export interface ITeamsSearchParams { contributingProjects: any []; officeHours?: string | null; teamFocusAreas: any []; + eventGuests?: any; } export interface ITeamDetailParams { diff --git a/utils/constants.ts b/utils/constants.ts index a62802a6..bcb70c95 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -272,6 +272,8 @@ export const TEAMS_ANALYTICS_EVENTS = { PROJECT_EDIT_CLICKED: 'project-edit-clicked', TEAM_OFFICEHOURS_LOGIN_BTN_CLICKED: 'team-officehours-login-btn-clicked', TEAM_DETAIL_ABOUT_SAVE: 'team-detail-about-save', + ON_CLICK_SEE_MORE_BUTTON_IRL_CONTRIBUTIONS: 'on_click_see_more_button_irl_contributions', + TEAM_DETAILS_ON_CLICK_IRL_CONTRIBUTIONS: 'team-details-on-click-irl-contributions', }; export const MEMBER_ANALYTICS_EVENTS = { @@ -312,6 +314,8 @@ export const MEMBER_ANALYTICS_EVENTS = { MEMBER_DETAIL_BIO_EDIT_CANCEL_CLICKED: 'member-detail-bio-edit-cancel-clicked', MEMBER_DETAIL_BIO_EDIT_SAVE_CLICKED: 'member-detail-bio-edit-save-clicked', MEMBER_DETAIL_BIO_EDIT_RECORD_SAVE: 'member-detail-bio-edit-record-save', + ON_CLICK_SEE_MORE_BUTTON_IRL_CONTRIBUTIONS: 'on_click_see_more_button_irl_contributions', + MEMBER_DETAILS_ON_CLICK_IRL_CONTRIBUTIONS: 'member-details-on-click-irl-contributions', }; export const IRL_ANALYTICS_EVENTS = { diff --git a/utils/member.utils.ts b/utils/member.utils.ts index 6aaee077..96345c67 100644 --- a/utils/member.utils.ts +++ b/utils/member.utils.ts @@ -628,3 +628,35 @@ export const validateBasicForms = async (formattedData: any) => { return errors; }; + +export function getFormattedDateString(startDate: string, endDate: string) { + const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + + try { + const [startDateOnly] = startDate.split('T'); + const [endDateOnly] = endDate.split('T'); + + const [startYear, startMonth] = startDateOnly.split('-'); + const [endYear, endMonth] = endDateOnly.split('-'); + + const startMonthName = monthNames[parseInt(startMonth, 10) - 1]; + const endMonthName = monthNames[parseInt(endMonth, 10) - 1]; + + const formattedStartYear = startYear.slice(2); + const formattedEndYear = endYear.slice(2); + + if (startDateOnly === endDateOnly) { + return `${startMonthName} ${formattedStartYear}`; + } else if (startMonth === endMonth && startYear === endYear) { + return `${startMonthName} ${formattedStartYear}`; + } else if (startYear === endYear) { + return `${startMonthName} - ${endMonthName} ${formattedStartYear}`; + } else { + return `${startMonthName} ${formattedStartYear} - ${endMonthName} ${formattedEndYear}`; + } + } catch { + return ''; + } +} + + diff --git a/utils/team.utils.ts b/utils/team.utils.ts index 13067bb0..54e9e302 100644 --- a/utils/team.utils.ts +++ b/utils/team.utils.ts @@ -233,4 +233,34 @@ export const teamRegisterDefault = { telegramHandler: '', blog: '', }, +} + +export function getFormattedDateString(startDate: string, endDate: string) { + const monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + + try { + const [startDateOnly] = startDate.split('T'); + const [endDateOnly] = endDate.split('T'); + + const [startYear, startMonth] = startDateOnly.split('-'); + const [endYear, endMonth] = endDateOnly.split('-'); + + const startMonthName = monthNames[parseInt(startMonth, 10) - 1]; + const endMonthName = monthNames[parseInt(endMonth, 10) - 1]; + + const formattedStartYear = startYear.slice(2); + const formattedEndYear = endYear.slice(2); + + if (startDateOnly === endDateOnly) { + return `${startMonthName} ${formattedStartYear}`; + } else if (startMonth === endMonth && startYear === endYear) { + return `${startMonthName} ${formattedStartYear}`; + } else if (startYear === endYear) { + return `${startMonthName} - ${endMonthName} ${formattedStartYear}`; + } else { + return `${startMonthName} ${formattedStartYear} - ${endMonthName} ${formattedEndYear}`; + } + } catch { + return ''; + } } \ No newline at end of file From 19a4dbaa8e4dbd5cbd542b955f7887e6dd0d7d62 Mon Sep 17 00:00:00 2001 From: yosuva Rajendran Date: Mon, 16 Dec 2024 11:59:56 +0530 Subject: [PATCH 2/2] Feat: Format event date --- .../member-irl-contributions.tsx | 18 ++++++++++------- .../team-details/team-irl-contributions.tsx | 20 ++++++++++++------- package-lock.json | 10 ++++++++++ package.json | 1 + 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/components/page/member-details/member-irl-contributions.tsx b/components/page/member-details/member-irl-contributions.tsx index 367c49b5..5343da17 100644 --- a/components/page/member-details/member-irl-contributions.tsx +++ b/components/page/member-details/member-irl-contributions.tsx @@ -6,10 +6,9 @@ import { IMember } from '@/types/members.types'; import { IAnalyticsUserInfo, IUserInfo } from '@/types/shared.types'; import { useMemberAnalytics } from '@/analytics/members.analytics'; import React from 'react'; -import { getFormattedDateString } from '@/utils/member.utils'; import { Tooltip } from '@/components/core/tooltip/tooltip'; import { usePathname, useRouter } from 'next/navigation'; -import { toZonedTime } from 'date-fns-tz'; +import { format, toZonedTime } from 'date-fns-tz'; interface IEvent { uid: string; @@ -81,13 +80,13 @@ const IrlMemberContribution = (props: IMemberRepositories) => { const handleEventClick = (details: any, role: any) => { analytics.onClickEventIrlContribution(userInfo); - // const isActive = new Date(details?.endDate) > new Date(); const isActive = checkTimeZone(details) const type = isActive ? "upcoming" : "past"; - const location = details.location.location ?? ""; + const location = details?.location?.location ?? ""; + const locationName = location.split(",")[0].trim(); const baseUrl = window.location.origin; - let url = `irl?location=${location}&type=${type}`; + let url = `irl?location=${locationName}&type=${type}`; if (role === "Attendee" && type === "upcoming") { url += `&attending=${details.name}`; @@ -110,6 +109,11 @@ const IrlMemberContribution = (props: IMemberRepositories) => { return endDateInTargetTimezone.getTime() > currentDateInTargetTimezone.getTime(); } + const getFormattedDateString = (date: string, timeZone: string) => { + const dateInTargetTimezone = toZonedTime(date, timeZone); + return format(dateInTargetTimezone, 'MMM dd', { timeZone }); + } + return ( <>
@@ -127,7 +131,7 @@ const IrlMemberContribution = (props: IMemberRepositories) => { {role}
- {visibleEvents.map((details: { name: any; startDate: any; endDate: any }, index: React.Key | null | undefined) => { + {visibleEvents.map((details: any, index: React.Key | null | undefined) => { const isActive = checkTimeZone(details); return (
{ } />
- {getFormattedDateString(details?.startDate, details?.endDate)} + {getFormattedDateString(details?.startDate, details?.location?.timezone)}
); diff --git a/components/page/team-details/team-irl-contributions.tsx b/components/page/team-details/team-irl-contributions.tsx index 561cbe77..a0e79b9d 100644 --- a/components/page/team-details/team-irl-contributions.tsx +++ b/components/page/team-details/team-irl-contributions.tsx @@ -9,7 +9,7 @@ import { getFormattedDateString } from '@/utils/member.utils'; import { Tooltip } from '@/components/core/tooltip/tooltip'; import { ITeam } from '@/types/teams.types'; import { useTeamAnalytics } from '@/analytics/teams.analytics'; -import { toZonedTime } from 'date-fns-tz'; +import { format, toZonedTime } from 'date-fns-tz'; interface IEvent { uid: string; @@ -73,13 +73,13 @@ const TeamIrlContributions = (props: ITeamMembers) => { const handleEventClick = (details: any, role: any) => { analytics.onClickTeamIrlContribution(userInfo); - // const isActive = new Date(details?.endDate) > new Date(); const isActive = checkTimeZone(details) const type = isActive ? "upcoming" : "past"; - const location = details.location.location ?? ""; + const location = details?.location?.location ?? ""; + const locationName = location?.split(",")[0].trim(); const baseUrl = window.location.origin; - let url = `irl?location=${location}&type=${type}`; + let url = `irl?location=${locationName}&type=${type}`; if (type === "past") { url += `&event=${details.slugURL}`; @@ -92,11 +92,17 @@ const TeamIrlContributions = (props: ITeamMembers) => { const checkTimeZone = (details: any) => { const timezone = details?.location?.timezone; - const endDateInTargetTimezone = toZonedTime(new Date(details?.endDate), timezone); + const endDateInTargetTimezone = toZonedTime(details?.endDate, timezone); const currentDateInTargetTimezone = toZonedTime(new Date(), timezone); return endDateInTargetTimezone.getTime() > currentDateInTargetTimezone.getTime(); } + + const getFormattedDateString = (date: string, timeZone: string) => { + const dateInTargetTimezone = toZonedTime(date, timeZone); + return format(dateInTargetTimezone, 'MMM dd', { timeZone }); + } + return ( <>
@@ -113,7 +119,7 @@ const TeamIrlContributions = (props: ITeamMembers) => { {role}
- {visibleEvents.map((details: { name: any; startDate: any; endDate: any }, index: React.Key | null | undefined) => { + {visibleEvents.map((details: any, index: React.Key | null | undefined) => { const isActive = checkTimeZone(details); return (
{ } />
- {getFormattedDateString(details?.startDate, details?.endDate)} + {getFormattedDateString(details?.startDate, details?.location?.timeZone)}
); diff --git a/package-lock.json b/package-lock.json index edc27051..49b3c78c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "@radix-ui/react-tooltip": "^1.0.7", "@testing-library/user-event": "^14.5.2", "@tinymce/tinymce-react": "^5.1.1", + "date-fns": "^4.1.0", "date-fns-tz": "^3.2.0", "embla-carousel-react": "^8.1.8", "isomorphic-dompurify": "^2.13.0", @@ -6351,6 +6352,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/date-fns-tz": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-3.2.0.tgz", diff --git a/package.json b/package.json index a764ebb7..411ae1b0 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "@radix-ui/react-tooltip": "^1.0.7", "@testing-library/user-event": "^14.5.2", "@tinymce/tinymce-react": "^5.1.1", + "date-fns": "^4.1.0", "date-fns-tz": "^3.2.0", "embla-carousel-react": "^8.1.8", "isomorphic-dompurify": "^2.13.0",