Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit eae5a1b

Browse files
committed
refactor: websocket logic in spotlights
1 parent 150026e commit eae5a1b

File tree

9 files changed

+131
-165
lines changed

9 files changed

+131
-165
lines changed

components/Layout/components/Banner.tsx

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import { ISpotlight, useNotify } from "@context/Notification";
2-
import { displayRemainingTime } from "@lib/time";
2+
import { compareDates, displayRemainingTime } from "@lib/time";
33
import { motion as Motion } from "framer-motion";
44
import Link from "next/link";
55
import { useEffect, useState } from "react";
66

77
function PlainBanner({ spotlight }: { spotlight: ISpotlight }) {
8-
const [remaining, setRemaining] = useState("");
8+
const [remaining, setRemaining] = useState(
9+
displayRemainingTime(spotlight.end)
10+
);
911

1012
useEffect(() => {
1113
const timerID = setInterval(() => {
@@ -74,33 +76,31 @@ function PlainBanner({ spotlight }: { spotlight: ISpotlight }) {
7476

7577
export default function Banner() {
7678
const { spotlight } = useNotify();
77-
const [lastSpotlight, setLastSpotlight] = useState(null);
7879

79-
useEffect(() => {
80-
if (spotlight) {
81-
setLastSpotlight(spotlight);
82-
}
83-
}, [spotlight]);
80+
if (spotlight) {
81+
const dateDifferenceinMs: number =
82+
new Date(spotlight.end).getTime() - new Date().getTime();
8483

85-
if (!lastSpotlight) {
86-
return null;
87-
} else if (spotlight) {
88-
return (
89-
<Motion.div
90-
initial={{ y: -100, height: 0 }}
91-
animate={{ y: 0, height: "auto" }}
92-
>
93-
<PlainBanner spotlight={spotlight} />
94-
</Motion.div>
95-
);
96-
} else {
97-
return (
98-
<Motion.div
99-
initial={{ y: 0, height: "auto" }}
100-
animate={{ y: -100, height: 0 }}
101-
>
102-
<PlainBanner spotlight={lastSpotlight} />
103-
</Motion.div>
104-
);
84+
if (dateDifferenceinMs > 0) {
85+
return (
86+
<Motion.div
87+
initial={{ y: -100, height: 0 }}
88+
animate={{ y: 0, height: "auto" }}
89+
>
90+
<PlainBanner spotlight={spotlight} />
91+
</Motion.div>
92+
);
93+
} else if (dateDifferenceinMs >= -1000) {
94+
return (
95+
<Motion.div
96+
initial={{ y: 0, height: "auto" }}
97+
animate={{ y: -100, height: 0 }}
98+
>
99+
<PlainBanner spotlight={spotlight} />
100+
</Motion.div>
101+
);
102+
}
105103
}
104+
105+
return null;
106106
}

context/Notification/NotifyContext.tsx

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,46 @@
1-
import { NotificationData, fetchers } from "./fetchers";
21
import { useContext, createContext, useState, useEffect } from "react";
3-
import { Socket, io } from "socket.io-client";
2+
import { Socket } from "phoenix";
3+
4+
export interface ISpotlight {
5+
id: number;
6+
name: string;
7+
badge_id: number;
8+
end: string;
9+
}
10+
11+
type NotificationData = {
12+
spotlight: ISpotlight;
13+
};
414

515
const NotifyContext = createContext({} as NotificationData);
616

717
export const useNotify = () => useContext<NotificationData>(NotifyContext);
818

9-
export function NotifyProvider({ children }) {
10-
const initialValue = Object.fromEntries(
11-
Object.entries(fetchers).map(([k, v]) => [k, v.initialValue])
12-
);
19+
const getPushUrl = () => {
20+
return process.env.NEXT_PUBLIC_WS_URL;
21+
};
1322

14-
const [socket, setSocket] = useState<Socket>(null);
15-
const [value, setValue] = useState(initialValue as NotificationData);
23+
export function NotifyProvider({ children }) {
24+
const [value, setValue] = useState({ spotlight: null } as NotificationData);
1625

1726
useEffect(() => {
18-
fetch("/api/notifications").finally(() => {
19-
const s = io();
27+
const socket = new Socket(getPushUrl(), {
28+
reconnectAfterMs: () => 10000,
29+
rejoinAfterMs: () => 10000,
30+
heartbeatIntervalMs: 30000,
31+
});
32+
33+
socket.connect();
34+
const channel = socket.channel("spotlight");
2035

21-
Object.keys(fetchers).forEach((key) => {
22-
s.on(key, (data) => {
23-
setValue({ ...value, [key]: data });
24-
});
25-
});
36+
channel.join();
2637

27-
setSocket(s);
38+
channel.on("spotlight", (data: ISpotlight) => {
39+
setValue({ ...value, spotlight: data });
2840
});
2941

3042
return () => {
31-
socket?.disconnect();
32-
setSocket(null);
43+
socket.disconnect();
3344
};
3445
}, []);
3546

context/Notification/WebSocket.jsx

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import { useState, useEffect } from "react";
2+
import { Socket } from "phoenix";
3+
4+
const getPushUrl = () => {
5+
return `ws://${process.env.NEXT_PUBLIC_API_URL}/socket`;
6+
};
7+
8+
function useWebSocket({ room, onNewMessage }) {
9+
const [channel, setChannel] = useState();
10+
const [connected, setConnected] = useState(false);
11+
12+
useEffect(() => {
13+
if (room) {
14+
const socket = new Socket(getPushUrl(), {
15+
reconnectAfterMs: () => 10000,
16+
rejoinAfterMs: () => 10000,
17+
heartbeatIntervalMs: 30000,
18+
});
19+
20+
socket.connect();
21+
const channel = socket.channel(room);
22+
23+
setChannel(channel);
24+
channel
25+
.join()
26+
.receive("ok", () => {
27+
setConnected(true);
28+
})
29+
.receive("error", () => {
30+
setConnected(false);
31+
});
32+
33+
if (onNewMessage) {
34+
channel.on("spotlight", onNewMessage);
35+
}
36+
37+
return () => {
38+
setConnected(false);
39+
socket.disconnect();
40+
};
41+
}
42+
43+
return () => {};
44+
}, []);
45+
46+
useEffect(() => {
47+
channel?.off("spotlight");
48+
channel?.on("spotlight", onNewMessage);
49+
}, [onNewMessage]);
50+
51+
return { connected, channel };
52+
}
53+
54+
export default useWebSocket;

context/Notification/fetchers.ts

Lines changed: 0 additions & 53 deletions
This file was deleted.

context/Notification/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
1-
export type { ISpotlight } from "./fetchers";
1+
export type { ISpotlight } from "./NotifyContext";
22
export { NotifyProvider, useNotify } from "./NotifyContext";

lib/time.js renamed to lib/time.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
export function displayRemainingTime(end) {
1+
export function displayRemainingTime(end: string) {
22
const now = new Date();
33
const endTime = new Date(end);
44
const timeDifference = endTime.getTime() - now.getTime();
@@ -15,3 +15,9 @@ export function displayRemainingTime(end) {
1515

1616
return `${formattedMinutes}:${formattedSeconds}`;
1717
}
18+
19+
export function compareDates(a: Date, b: Date) {
20+
if (a > b) return 1;
21+
if (a < b) return -1;
22+
return 0;
23+
}

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"jsqr": "^1.4.0",
3838
"lottie-web": "^5.8.1",
3939
"next": "^13.4.19",
40+
"phoenix": "^1.7.7",
4041
"qrcode": "^1.5.1",
4142
"react": "^18.2.0",
4243
"react-cool-inview": "^2.0.8",

pages/api/notifications.ts

Lines changed: 0 additions & 64 deletions
This file was deleted.

0 commit comments

Comments
 (0)