Skip to content

Commit 9e75b9a

Browse files
committed
fix (pwa): middleware issue
1 parent d5aa2c8 commit 9e75b9a

File tree

5 files changed

+130
-83
lines changed

5 files changed

+130
-83
lines changed

src/client/components/LayoutWrapper.js

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,29 @@ export default function LayoutWrapper({ children }) {
196196
}
197197
}, [])
198198

199+
useEffect(() => {
200+
// This effect runs only on the client side, after the component mounts.
201+
if (
202+
"serviceWorker" in navigator &&
203+
process.env.NODE_ENV === "production"
204+
) {
205+
// The 'load' event ensures that SW registration doesn't delay page rendering.
206+
window.addEventListener("load", function () {
207+
navigator.serviceWorker.register("/sw.js").then(
208+
function (registration) {
209+
console.log(
210+
"ServiceWorker registration successful with scope: ",
211+
registration.scope
212+
)
213+
},
214+
function (err) {
215+
console.log("ServiceWorker registration failed: ", err)
216+
}
217+
)
218+
})
219+
}
220+
}, [])
221+
199222
useEffect(() => {
200223
const handleEscape = (e) => {
201224
if (e.key === "Escape") {

src/client/components/Sidebar.js

Lines changed: 86 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -65,45 +65,18 @@ const SidebarContent = ({
6565
onNotificationsOpen,
6666
unreadCount,
6767
isMobile = false,
68-
onMobileClose = () => {}
68+
onMobileClose = () => {},
69+
installPrompt,
70+
handleInstallClick
6971
}) => {
7072
const pathname = usePathname()
7173
const [userDetails, setUserDetails] = useState(null)
7274
const [isHelpModalOpen, setHelpModalOpen] = useState(false)
73-
const [installPrompt, setInstallPrompt] = useState(null)
7475
const [isUserMenuOpen, setUserMenuOpen] = useState(false)
7576
const userMenuRef = useRef(null)
7677

7778
useClickOutside(userMenuRef, () => setUserMenuOpen(false))
7879

79-
useEffect(() => {
80-
const handleBeforeInstallPrompt = (e) => {
81-
// Prevent the mini-infobar from appearing on mobile
82-
e.preventDefault()
83-
// Stash the event so it can be triggered later.
84-
setInstallPrompt(e)
85-
}
86-
87-
window.addEventListener(
88-
"beforeinstallprompt",
89-
handleBeforeInstallPrompt
90-
)
91-
92-
return () => {
93-
window.removeEventListener(
94-
"beforeinstallprompt",
95-
handleBeforeInstallPrompt
96-
)
97-
}
98-
}, [])
99-
100-
const handleInstallClick = async () => {
101-
if (!installPrompt) return
102-
const result = await installPrompt.prompt()
103-
console.log(`Install prompt was: ${result.outcome}`)
104-
setInstallPrompt(null)
105-
}
106-
10780
useEffect(() => {
10881
fetch("/api/user/profile")
10982
.then((res) => (res.ok ? res.json() : null))
@@ -398,55 +371,89 @@ const Sidebar = ({
398371
unreadCount,
399372
isMobileOpen,
400373
onMobileClose
401-
}) => (
402-
<>
403-
{/* Mobile Sidebar */}
404-
<AnimatePresence>
405-
{isMobileOpen && (
406-
<>
407-
<motion.div
408-
className="fixed inset-0 bg-black/60 z-40 md:hidden"
409-
initial={{ opacity: 0 }}
410-
animate={{ opacity: 1 }}
411-
exit={{ opacity: 0 }}
412-
onClick={onMobileClose}
413-
/>
414-
<motion.div
415-
className="fixed top-0 left-0 h-screen w-[260px] bg-black p-3 text-neutral-200 border-r border-neutral-800/50 z-50 md:hidden"
416-
initial={{ x: "-100%" }}
417-
animate={{ x: 0 }}
418-
exit={{ x: "-100%" }}
419-
transition={{
420-
type: "spring",
421-
stiffness: 300,
422-
damping: 30
423-
}}
424-
>
425-
<SidebarContent
426-
isCollapsed={false}
427-
onMobileClose={onMobileClose}
428-
onNotificationsOpen={onNotificationsOpen}
429-
unreadCount={unreadCount}
430-
isMobile={true}
374+
}) => {
375+
const [installPrompt, setInstallPrompt] = useState(null)
376+
377+
useEffect(() => {
378+
const handleBeforeInstallPrompt = (e) => {
379+
e.preventDefault()
380+
setInstallPrompt(e)
381+
}
382+
383+
window.addEventListener(
384+
"beforeinstallprompt",
385+
handleBeforeInstallPrompt
386+
)
387+
388+
return () => {
389+
window.removeEventListener(
390+
"beforeinstallprompt",
391+
handleBeforeInstallPrompt
392+
)
393+
}
394+
}, [])
395+
396+
const handleInstallClick = async () => {
397+
if (!installPrompt) return
398+
const result = await installPrompt.prompt()
399+
console.log(`Install prompt was: ${result.outcome}`)
400+
setInstallPrompt(null) // The prompt can only be used once.
401+
}
402+
403+
return (
404+
<>
405+
{/* Mobile Sidebar */}
406+
<AnimatePresence>
407+
{isMobileOpen && (
408+
<>
409+
<motion.div
410+
className="fixed inset-0 bg-black/60 z-40 md:hidden"
411+
initial={{ opacity: 0 }}
412+
animate={{ opacity: 1 }}
413+
exit={{ opacity: 0 }}
414+
onClick={onMobileClose}
431415
/>
432-
</motion.div>
433-
</>
434-
)}
435-
</AnimatePresence>
416+
<motion.div
417+
className="fixed top-0 left-0 h-screen w-[260px] bg-black p-3 text-neutral-200 border-r border-neutral-800/50 z-50 md:hidden"
418+
initial={{ x: "-100%" }}
419+
animate={{ x: 0 }}
420+
exit={{ x: "-100%" }}
421+
transition={{
422+
type: "spring",
423+
stiffness: 300,
424+
damping: 30
425+
}}
426+
>
427+
<SidebarContent
428+
isCollapsed={false}
429+
onMobileClose={onMobileClose}
430+
onNotificationsOpen={onNotificationsOpen}
431+
unreadCount={unreadCount}
432+
isMobile={true}
433+
installPrompt={installPrompt}
434+
handleInstallClick={handleInstallClick}
435+
/>
436+
</motion.div>
437+
</>
438+
)}
439+
</AnimatePresence>
436440

437-
{/* Desktop Sidebar */}
438-
<motion.div
439-
animate={{ width: isCollapsed ? 80 : 260 }}
440-
transition={{ type: "spring", stiffness: 300, damping: 30 }}
441-
className="hidden md:flex fixed top-0 left-0 h-screen bg-black flex-col p-3 text-neutral-200 border-r border-neutral-800/50 z-40"
442-
>
443-
<SidebarContent
444-
isCollapsed={isCollapsed}
445-
onToggle={onToggle}
446-
onNotificationsOpen={onNotificationsOpen}
447-
unreadCount={unreadCount}
448-
/>
449-
</motion.div>
450-
</>
451-
)
441+
{/* Desktop Sidebar */}
442+
<motion.div
443+
animate={{ width: isCollapsed ? 80 : 260 }}
444+
transition={{ type: "spring", stiffness: 300, damping: 30 }}
445+
className="hidden md:flex fixed top-0 left-0 h-screen bg-black flex-col p-3 text-neutral-200 border-r border-neutral-800/50 z-40"
446+
>
447+
<SidebarContent
448+
isCollapsed={isCollapsed}
449+
onToggle={onToggle}
450+
onNotificationsOpen={onNotificationsOpen}
451+
unreadCount={unreadCount}
452+
installPrompt={installPrompt}
453+
handleInstallClick={handleInstallClick}
454+
/>
455+
</motion.div>
456+
</>
457+
)
458+
}
452459
export default Sidebar

src/client/middleware.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ export const config = {
3838
* - _next/image (image optimization files)
3939
* - favicon.ico, sitemap.xml, robots.txt (metadata files)
4040
* - api (API routes)
41+
* - PWA files (manifest, icons, service worker, workbox)
4142
*/
42-
"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|api).*)"
43+
"/((?!_next/static|_next/image|favicon.ico|sitemap.xml|robots.txt|api|manifest.json|sw.js|workbox-.*\\.js$|.*\\.png$).*)"
4344
]
44-
}
45+
}

src/client/next.config.js

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,24 @@ const withPWA = nextPWA({
77
dest: "public",
88
disable: process.env.NODE_ENV === "development",
99
register: true,
10-
skipWaiting: false,
10+
skipWaiting: true,
11+
exclude: [
12+
// add buildExcludes here
13+
({ asset, compilation }) => {
14+
if (
15+
asset.name.startsWith("server/") ||
16+
asset.name.match(
17+
/^((app-|^)build-manifest\.json|react-loadable-manifest\.json)$/
18+
)
19+
) {
20+
return true
21+
}
22+
if (process.env.NODE_ENV == "development" && !asset.name.startsWith("static/runtime/")) {
23+
return true
24+
}
25+
return false
26+
}
27+
],
1128
runtimeCaching: [
1229
// Cache Google Fonts
1330
{

src/client/public/site.webmanifest

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)