Skip to content

Commit 3f2f467

Browse files
authoredMar 20, 2025··
feat/forward-search-params (#676)
include utm params in tickets link
1 parent 6b1a6ea commit 3f2f467

File tree

9 files changed

+326
-165
lines changed

9 files changed

+326
-165
lines changed
 

‎package-lock.json

+128-45
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json

+3-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
"dependencies": {
77
"@egjs/flicking-plugins": "^4.7.1",
88
"@egjs/react-flicking": "^4.12.0",
9-
"@faker-js/faker": "9.6.0",
109
"@sentry/react": "^9.5.0",
1110
"@sentry/tracing": "^7.120.3",
1211
"@types/node": "^22.13.1",
@@ -87,8 +86,11 @@
8786
]
8887
},
8988
"devDependencies": {
89+
"@faker-js/faker": "9.6.0",
90+
"@testing-library/dom": "^10.4.0",
9091
"@testing-library/jest-dom": "^6.6.3",
9192
"@testing-library/react": "^16.2.0",
93+
"@testing-library/react-hooks": "^7.0.2",
9294
"@testing-library/user-event": "^14.6.0",
9395
"@types/google-map-react": "^2.1.10",
9496
"@types/jest": "^29.5.13",

‎src/2023/Home/components/ActionButtons/ActionButtons.tsx

+22-31
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import Button from "../../../../components/UI/Button";
44
import styled from "styled-components";
55
import { BIG_BREAKPOINT } from "../../../../constants/BreakPoints";
66
import { gaEventTracker } from "../../../../components/analytics/Analytics";
7+
import { useDateInterval } from "../../../../hooks/useDateInterval";
8+
import { useUrlBuilder } from "../../../../services/urlBuilder";
79

810
const StyledActionDiv = styled.div`
911
display: flex;
@@ -16,16 +18,8 @@ const StyledActionDiv = styled.div`
1618
`;
1719

1820
const ActionButtons: FC<React.PropsWithChildren<unknown>> = () => {
19-
const ticketStartDay = new Date(data.tickets.startDay);
20-
const ticketEndDay = new Date(data.tickets.endDay);
21-
const CFPStartDay = new Date(data.cfp.startDay);
22-
const CFPEndDay = new Date(data.cfp.endDay);
23-
const sponsorshipStartDay = new Date(data.tickets.startDay);
24-
const sponsorshipEndDay = new Date(data.tickets.endDay);
25-
const today = new Date();
26-
27-
const isBetween = (startDay: Date, endDay: Date): boolean =>
28-
startDay < new Date() && endDay > today;
21+
const { isTicketsDisabled, isSponsorDisabled, isCfpDisabled } =
22+
useDateInterval(new Date(), data);
2923

3024
const trackSponsorshipInfo = useCallback(() => {
3125
gaEventTracker("sponsorship", "sponsorship");
@@ -41,27 +35,24 @@ const ActionButtons: FC<React.PropsWithChildren<unknown>> = () => {
4135

4236
return (
4337
<StyledActionDiv>
44-
{isBetween(ticketStartDay, ticketEndDay) && (
45-
<Button
46-
onClick={trackTickets}
47-
text="🎟️ Buy Tickets"
48-
link="https://tickets.devbcn.com/event/devbcn-2023"
49-
/>
50-
)}
51-
{isBetween(CFPStartDay, CFPEndDay) && (
52-
<Button
53-
onClick={trackCFP}
54-
text="📢 Call For Papers"
55-
link={data.cfp.link}
56-
/>
57-
)}
58-
{isBetween(sponsorshipStartDay, sponsorshipEndDay) && (
59-
<Button
60-
onClick={trackSponsorshipInfo}
61-
text="🤝 Sponsorship"
62-
link="mailto:sponsors@devbcn.com?subject=devBcn sponsorship"
63-
/>
64-
)}
38+
<Button
39+
onClick={trackTickets}
40+
text="🎟️ Buy Tickets"
41+
link={useUrlBuilder("https://tickets.devbcn.com/event/devbcn-2023")}
42+
disabled={isTicketsDisabled}
43+
/>
44+
<Button
45+
onClick={trackCFP}
46+
text="📢 Call For Papers"
47+
link={data.cfp.link}
48+
disabled={isCfpDisabled}
49+
/>
50+
<Button
51+
onClick={trackSponsorshipInfo}
52+
text="🤝 Sponsorship"
53+
link="mailto:sponsors@devbcn.com?subject=devBcn sponsorship"
54+
disabled={isSponsorDisabled}
55+
/>
6556
</StyledActionDiv>
6657
);
6758
};
+48-56
Original file line numberDiff line numberDiff line change
@@ -1,67 +1,59 @@
1-
import {FC, useCallback} from "react";
1+
import { FC, useCallback } from "react";
22
import data from "../../../data/2024.json";
33
import styled from "styled-components";
4-
import {BIG_BREAKPOINT} from "../../../constants/BreakPoints";
5-
import {gaEventTracker} from "../../../components/analytics/Analytics";
4+
import { BIG_BREAKPOINT } from "../../../constants/BreakPoints";
5+
import { gaEventTracker } from "../../../components/analytics/Analytics";
66
import Button from "../../../components/UI/Button";
7+
import { useDateInterval } from "../../../hooks/useDateInterval";
8+
import {useUrlBuilder} from "../../../services/urlBuilder";
79

810
const StyledActionDiv = styled.div`
9-
display: flex;
10-
text-align: center;
11+
display: flex;
12+
text-align: center;
1113
12-
@media (max-width: ${BIG_BREAKPOINT}px) {
13-
flex-direction: column;
14-
width: 75%;
15-
}
14+
@media (max-width: ${BIG_BREAKPOINT}px) {
15+
flex-direction: column;
16+
width: 75%;
17+
}
1618
`;
1719

1820
const ActionButtons: FC<React.PropsWithChildren<unknown>> = () => {
19-
const ticketStartDay = new Date(data.tickets.startDay);
20-
const ticketEndDay = new Date(data.tickets.endDay);
21-
const CFPStartDay = new Date(data.cfp.startDay);
22-
const CFPEndDay = new Date(data.cfp.endDay);
23-
const sponsorshipStartDay = new Date(data.sponsors.startDate);
24-
const sponsorshipEndDay = new Date(data.sponsors.endDate);
25-
const today = new Date();
26-
27-
const isBetween = (startDay: Date, endDay: Date): boolean =>
28-
startDay < new Date() && endDay > today;
29-
30-
const trackSponsorshipInfo = useCallback(() => {
31-
gaEventTracker("sponsorship", "sponsorship");
32-
}, []);
33-
34-
const trackTickets = useCallback(() => {
35-
gaEventTracker("ticket", "tickets");
36-
}, []);
37-
38-
const trackCFP = useCallback(() => {
39-
gaEventTracker("CFP", "CFP");
40-
}, []);
41-
42-
return (
43-
<StyledActionDiv>
44-
<Button
45-
onClick={trackTickets}
46-
text="🎟️ Buy Tickets"
47-
link="https://tickets.devbcn.com/event/devbcn-2024"
48-
disabled={!isBetween(ticketStartDay, ticketEndDay)}
49-
/>
50-
{isBetween(CFPStartDay, CFPEndDay) && (
51-
<Button
52-
onClick={trackCFP}
53-
text="📢 Call For Papers"
54-
link={data.cfp.link}
55-
/>
56-
)}
57-
{isBetween(sponsorshipStartDay, sponsorshipEndDay) && (
58-
<Button
59-
onClick={trackSponsorshipInfo}
60-
text="🤝 Sponsorship"
61-
link="https://www.devbcn.com/sponsorship"
62-
/>
63-
)}
64-
</StyledActionDiv>
65-
);
21+
const { isSponsorDisabled, isCfpDisabled, isTicketsDisabled } =
22+
useDateInterval(new Date(), data);
23+
24+
const trackSponsorshipInfo = useCallback(() => {
25+
gaEventTracker("sponsorship", "sponsorship");
26+
}, []);
27+
28+
const trackTickets = useCallback(() => {
29+
gaEventTracker("ticket", "tickets");
30+
}, []);
31+
32+
const trackCFP = useCallback(() => {
33+
gaEventTracker("CFP", "CFP");
34+
}, []);
35+
36+
return (
37+
<StyledActionDiv>
38+
<Button
39+
onClick={trackTickets}
40+
text="🎟️ Buy Tickets"
41+
link={useUrlBuilder("https://tickets.devbcn.com/event/devbcn-2024")}
42+
disabled={isTicketsDisabled}
43+
/>
44+
<Button
45+
onClick={trackCFP}
46+
text="📢 Call For Papers"
47+
link={data.cfp.link}
48+
disabled={isCfpDisabled}
49+
/>
50+
<Button
51+
onClick={trackSponsorshipInfo}
52+
text="🤝 Sponsorship"
53+
link="https://www.devbcn.com/sponsorship"
54+
disabled={isSponsorDisabled}
55+
/>
56+
</StyledActionDiv>
57+
);
6658
};
6759
export default ActionButtons;

‎src/hooks/useDateInterval.test.ts

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { renderHook } from '@testing-library/react-hooks';
2+
import { useDateInterval } from './useDateInterval';
3+
4+
const today = new Date('2023-10-10');
5+
6+
const edition = {
7+
tickets: {
8+
startDay: '2023-10-01',
9+
endDay: '2023-10-15',
10+
},
11+
cfp: {
12+
startDay: '2023-09-01',
13+
endDay: '2023-09-30',
14+
},
15+
sponsors: {
16+
startDate: '2023-10-05',
17+
endDate: '2023-10-20',
18+
},
19+
};
20+
21+
describe('useDateInterval', () => {
22+
it('should return correct disabled states for tickets, cfp, and sponsors', () => {
23+
const { result } = renderHook(() => useDateInterval(today, edition));
24+
25+
expect(result.current.isTicketsDisabled).toBe(false);
26+
expect(result.current.isCfpDisabled).toBe(true);
27+
expect(result.current.isSponsorDisabled).toBe(false);
28+
});
29+
});

‎src/hooks/useDateInterval.ts

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { isWithinInterval } from "date-fns";
2+
3+
type DateInterval = {
4+
tickets:{
5+
startDay: string,
6+
endDay: string,
7+
},
8+
cfp:{
9+
startDay: string,
10+
endDay: string,
11+
},
12+
sponsors:{
13+
startDate: string,
14+
endDate: string,
15+
}
16+
}
17+
18+
export const useDateInterval = (today: Date, edition: DateInterval) => {
19+
const ticketStartDay = new Date(edition.tickets.startDay);
20+
const ticketEndDay = new Date(edition.tickets.endDay);
21+
const CFPStartDay = new Date(edition.cfp.startDay);
22+
const CFPEndDay = new Date(edition.cfp.endDay);
23+
const sponsorStartDay = new Date(edition.sponsors.startDate);
24+
const sponsorEndDay = new Date(edition.sponsors.endDate);
25+
26+
return {
27+
isTicketsDisabled: !isWithinInterval(today, {
28+
start: ticketStartDay,
29+
end: ticketEndDay,
30+
}),
31+
isCfpDisabled: !isWithinInterval(today, {
32+
start: CFPStartDay,
33+
end: CFPEndDay,
34+
}),
35+
isSponsorDisabled: !isWithinInterval(today, {
36+
start: sponsorStartDay,
37+
end: sponsorEndDay,
38+
}),
39+
};
40+
};

‎src/services/urlBuilder.test.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { useUrlBuilder } from './urlBuilder';
2+
3+
// Mock window.location for the test
4+
const originalLocation = window.location;
5+
delete window.location;
6+
window.location = {
7+
origin: 'http://localhost',
8+
search: '?query=123',
9+
} as any;
10+
11+
describe('useUrlBuilder', () => {
12+
afterAll(() => {
13+
// Restore original window.location after tests
14+
window.location = originalLocation;
15+
});
16+
17+
it('should append the current search params to the URL', () => {
18+
const url = 'http://example.com/path';
19+
const result = useUrlBuilder(url);
20+
expect(result).toBe('http://example.com/path?query=123');
21+
});
22+
23+
it('should handle URLs without a path', () => {
24+
const url = 'http://example.com';
25+
const result = useUrlBuilder(url);
26+
expect(result).toBe('http://example.com/?query=123');
27+
});
28+
});

‎src/services/urlBuilder.ts

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const useUrlBuilder = (url: string) => {
2+
const returnUrl = new URL(url, window.location.origin);
3+
returnUrl.search = window.location.search;
4+
return returnUrl.toString();
5+
}

‎src/views/Home/components/ActionButtons/ActionButtons.tsx

+23-32
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import {FC, useCallback} from "react";
1+
import { FC, useCallback } from "react";
22
import data from "../../../../data/2025.json";
33
import Button from "../../../../components/UI/Button";
44
import styled from "styled-components";
5-
import {isWithinInterval} from "date-fns";
6-
import {BIG_BREAKPOINT} from "../../../../constants/BreakPoints";
7-
import {gaEventTracker} from "../../../../components/analytics/Analytics";
5+
import { BIG_BREAKPOINT } from "../../../../constants/BreakPoints";
6+
import { gaEventTracker } from "../../../../components/analytics/Analytics";
7+
import { useDateInterval } from "../../../../hooks/useDateInterval";
8+
import {useUrlBuilder} from "../../../../services/urlBuilder";
89

910
const StyledActionDiv = styled.div`
1011
display: flex;
@@ -17,17 +18,8 @@ const StyledActionDiv = styled.div`
1718
`;
1819

1920
const ActionButtons: FC<React.PropsWithChildren<unknown>> = () => {
20-
const ticketStartDay = new Date(data.tickets.startDay);
21-
const ticketEndDay = new Date(data.tickets.endDay);
22-
const CFPStartDay = new Date(data.cfp.startDay);
23-
const CFPEndDay = new Date(data.cfp.endDay);
24-
const sponsorshipStartDay = new Date(data.sponsors.startDate);
25-
const sponsorshipEndDay = new Date(data.sponsors.endDate);
26-
const today = new Date();
27-
28-
29-
const isBetween = (startDay: Date, endDay: Date): boolean =>
30-
isWithinInterval(today, {start: startDay, end:endDay});
21+
const { isTicketsDisabled, isSponsorDisabled, isCfpDisabled } =
22+
useDateInterval(new Date(), data);
3123

3224
const trackSponsorshipInfo = useCallback(() => {
3325
gaEventTracker("sponsorship", "sponsorship");
@@ -41,30 +33,29 @@ const ActionButtons: FC<React.PropsWithChildren<unknown>> = () => {
4133
gaEventTracker("CFP", "CFP");
4234
}, []);
4335

44-
4536
return (
4637
<StyledActionDiv>
4738
<Button
4839
onClick={trackTickets}
4940
text="🎟️ Buy Tickets"
5041
subtext="February 1st, 2025"
51-
link="https://tickets.devbcn.com/event/devbcn-2025"
52-
disabled={!isBetween(ticketStartDay, ticketEndDay)}
42+
link={useUrlBuilder("https://tickets.devbcn.com/event/devbcn-2025")}
43+
disabled={isTicketsDisabled}
44+
/>
45+
<Button
46+
onClick={trackCFP}
47+
text="📢 Call For Papers"
48+
subtext="January 1st, 2025"
49+
link={data.cfp.link}
50+
disabled={isCfpDisabled}
51+
/>
52+
<Button
53+
onClick={trackSponsorshipInfo}
54+
text="🤝 Sponsorship"
55+
target="_self"
56+
link="/sponsorship"
57+
disabled={isSponsorDisabled}
5358
/>
54-
<Button
55-
onClick={trackCFP}
56-
text="📢 Call For Papers"
57-
subtext="January 1st, 2025"
58-
link={data.cfp.link}
59-
disabled={!isBetween(CFPStartDay, CFPEndDay)}
60-
/>
61-
<Button
62-
onClick={trackSponsorshipInfo}
63-
text="🤝 Sponsorship"
64-
target="_self"
65-
link="/sponsorship"
66-
disabled={!isBetween(sponsorshipStartDay, sponsorshipEndDay)}
67-
/>
6859
</StyledActionDiv>
6960
);
7061
};

0 commit comments

Comments
 (0)
Please sign in to comment.