Skip to content

Commit cba5e0e

Browse files
committed
fix: An error occurred on client
1 parent 5ab95e9 commit cba5e0e

6 files changed

Lines changed: 131 additions & 25 deletions

File tree

packages/webapp/components/notificationPanel/desktop/NotificationPanel.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ export const NotificationPanel = () => {
1919
setNotificationActiveTab
2020
} = useStore((state) => state)
2121

22-
useNotificationSummary()
22+
useNotificationSummary({ mobile: false })
2323
useNotificationTabData()
2424

2525
const activeTabNotifList = useMemo(() => {

packages/webapp/components/notificationPanel/hooks/useNotificationSummary.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ import { getNotificationsSummary } from '@api'
44
import { useAuthStore, useStore } from '@stores'
55
import { TNotificationSummary } from '@types'
66
import { useDropdown } from '@components/ui/Dropdown'
7+
import { useModalBottomToTopOptional } from '@components/ui'
78

8-
export const useNotificationSummary = () => {
9+
export const useNotificationSummary = ({ mobile = false }: { mobile: boolean }) => {
910
const { workspaceId } = useStore((state) => state.settings)
1011
const user = useAuthStore((state) => state.profile)
1112
const {
@@ -16,7 +17,9 @@ export const useNotificationSummary = () => {
1617
setNotificationTab,
1718
setNotificationPage
1819
} = useStore((state) => state)
19-
const { isOpen } = useDropdown() || { isOpen: false }
20+
const modalContext = mobile ? useModalBottomToTopOptional() : null
21+
const dropdownContext = mobile ? null : useDropdown()
22+
const isOpen = modalContext?.isOpen || dropdownContext?.isOpen || false
2023

2124
const { request: summaryRequest } = useApi(getNotificationsSummary, null, false)
2225

packages/webapp/components/notificationPanel/mobile/NotificationModal.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { useNotificationTabData } from '../hooks/useNotificationTabData'
1212
const NotificationModal = () => {
1313
const { loadingNotification, notifications, notificationActiveTab } = useStore((state) => state)
1414

15-
useNotificationSummary()
15+
useNotificationSummary({ mobile: true })
1616
useNotificationTabData()
1717

1818
const activeTabNotifList = useMemo(() => {

packages/webapp/components/ui/ModalBottomToTop.tsx

Lines changed: 53 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import React, { useCallback, useImperativeHandle, forwardRef, useState, useEffect } from 'react'
22
import { twMerge } from 'tailwind-merge'
3+
import { useModalBottomToTopOptional } from './ModalBottomToTopContext'
34

45
interface ModalBottomToTopProps {
56
modalId?: string
@@ -32,21 +33,35 @@ export const ModalBottomToTop = forwardRef<unknown, ModalBottomToTopProps>(
3233
const [startHeight, setStartHeight] = useState<number>(0)
3334
const [isTouched, setIsTouched] = useState<boolean>(false)
3435

36+
// Use context if available, otherwise rely on checkbox state
37+
const modalContext = useModalBottomToTopOptional()
38+
3539
const handleCheckboxChange = useCallback(
3640
(event: React.ChangeEvent<HTMLInputElement>) => {
37-
if (event.target.checked) {
41+
const isChecked = event.target.checked
42+
43+
if (isChecked) {
3844
window.history.pushState({ modal: modalId }, '')
3945
} else {
4046
if (window.history.state?.modal === modalId) {
4147
window.history.back()
4248
}
4349
}
4450

51+
// Update context if available
52+
if (modalContext) {
53+
if (isChecked) {
54+
modalContext.openModal()
55+
} else {
56+
modalContext.closeModal()
57+
}
58+
}
59+
4560
if (onModalStateChange) {
46-
onModalStateChange(event.target.checked)
61+
onModalStateChange(isChecked)
4762
}
4863
},
49-
[onModalStateChange, modalId]
64+
[onModalStateChange, modalId, modalContext]
5065
)
5166

5267
const handleTouchStart = useCallback(
@@ -91,6 +106,13 @@ export const ModalBottomToTop = forwardRef<unknown, ModalBottomToTopProps>(
91106
}
92107
}, [isDragging])
93108

109+
// Sync context state with checkbox
110+
useEffect(() => {
111+
if (modalContext && checkboxRef.current) {
112+
checkboxRef.current.checked = modalContext.isOpen
113+
}
114+
}, [modalContext?.isOpen])
115+
94116
useEffect(() => {
95117
const handlePopState = () => {
96118
if (checkboxRef.current?.checked) {
@@ -105,22 +127,32 @@ export const ModalBottomToTop = forwardRef<unknown, ModalBottomToTopProps>(
105127
return () => window.removeEventListener('popstate', handlePopState)
106128
}, [handleCheckboxChange])
107129

108-
useImperativeHandle(ref, () => ({
109-
check: () => {
110-
if (checkboxRef.current) {
111-
checkboxRef.current.checked = true
112-
handleCheckboxChange({ target: { checked: true } } as React.ChangeEvent<HTMLInputElement>)
113-
}
114-
},
115-
uncheck: () => {
116-
if (checkboxRef.current) {
117-
checkboxRef.current.checked = false
118-
handleCheckboxChange({
119-
target: { checked: false }
120-
} as React.ChangeEvent<HTMLInputElement>)
130+
useImperativeHandle(
131+
ref,
132+
() => ({
133+
check: () => {
134+
if (modalContext) {
135+
modalContext.openModal()
136+
} else if (checkboxRef.current) {
137+
checkboxRef.current.checked = true
138+
handleCheckboxChange({
139+
target: { checked: true }
140+
} as React.ChangeEvent<HTMLInputElement>)
141+
}
142+
},
143+
uncheck: () => {
144+
if (modalContext) {
145+
modalContext.closeModal()
146+
} else if (checkboxRef.current) {
147+
checkboxRef.current.checked = false
148+
handleCheckboxChange({
149+
target: { checked: false }
150+
} as React.ChangeEvent<HTMLInputElement>)
151+
}
121152
}
122-
}
123-
}))
153+
}),
154+
[modalContext, handleCheckboxChange]
155+
)
124156

125157
return (
126158
<div className={twMerge('bottom-to-top-modal', className)}>
@@ -153,7 +185,7 @@ export const ModalBottomToTop = forwardRef<unknown, ModalBottomToTopProps>(
153185
onTouchStart={handleTouchStart}
154186
onTouchMove={handleTouchMove}
155187
onTouchEnd={handleTouchEnd}>
156-
<div className="h-2 w-24 rounded-md bg-neutral group-hover:drop-shadow-md" />
188+
<div className="bg-neutral h-2 w-24 rounded-md group-hover:drop-shadow-md" />
157189
</div>
158190
{children}
159191
</div>
@@ -162,7 +194,7 @@ export const ModalBottomToTop = forwardRef<unknown, ModalBottomToTopProps>(
162194
<div
163195
ref={contentRef}
164196
className={twMerge(
165-
'modal-content sticky bottom-0 left-0 right-0 z-50 w-full max-w-md translate-y-full rounded-t-2xl bg-white shadow-[0_-4px_6px_-1px_rgba(0,0,0,0.1)] transition-transform duration-300 ease-in-out peer-checked:translate-y-0',
197+
'modal-content sticky right-0 bottom-0 left-0 z-50 w-full max-w-md translate-y-full rounded-t-2xl bg-white shadow-[0_-4px_6px_-1px_rgba(0,0,0,0.1)] transition-transform duration-300 ease-in-out peer-checked:translate-y-0',
166198
contentClassName
167199
)}
168200
style={{ height: modalHeight ? `${modalHeight}px` : '300px', maxHeight: '100%' }}>
@@ -174,7 +206,7 @@ export const ModalBottomToTop = forwardRef<unknown, ModalBottomToTopProps>(
174206
onTouchStart={handleTouchStart}
175207
onTouchMove={handleTouchMove}
176208
onTouchEnd={handleTouchEnd}>
177-
<div className="h-2 w-24 rounded-md bg-neutral group-hover:drop-shadow-md" />
209+
<div className="bg-neutral h-2 w-24 rounded-md group-hover:drop-shadow-md" />
178210
</div>
179211
{children}
180212
</div>
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React, { createContext, useContext, useState, useCallback, ReactNode } from 'react'
2+
3+
interface ModalBottomToTopContextValue {
4+
isOpen: boolean
5+
openModal: () => void
6+
closeModal: () => void
7+
toggleModal: () => void
8+
}
9+
10+
const ModalBottomToTopContext = createContext<ModalBottomToTopContextValue | null>(null)
11+
12+
interface ModalBottomToTopProviderProps {
13+
children: ReactNode
14+
onModalStateChange?: (isOpen: boolean) => void
15+
}
16+
17+
export const ModalBottomToTopProvider = ({
18+
children,
19+
onModalStateChange
20+
}: ModalBottomToTopProviderProps) => {
21+
const [isOpen, setIsOpen] = useState(false)
22+
23+
const openModal = useCallback(() => {
24+
setIsOpen(true)
25+
onModalStateChange?.(true)
26+
}, [onModalStateChange])
27+
28+
const closeModal = useCallback(() => {
29+
setIsOpen(false)
30+
onModalStateChange?.(false)
31+
}, [onModalStateChange])
32+
33+
const toggleModal = useCallback(() => {
34+
setIsOpen((prev) => {
35+
const newState = !prev
36+
onModalStateChange?.(newState)
37+
return newState
38+
})
39+
}, [onModalStateChange])
40+
41+
return (
42+
<ModalBottomToTopContext.Provider
43+
value={{
44+
isOpen,
45+
openModal,
46+
closeModal,
47+
toggleModal
48+
}}>
49+
{children}
50+
</ModalBottomToTopContext.Provider>
51+
)
52+
}
53+
54+
export const useModalBottomToTop = () => {
55+
const context = useContext(ModalBottomToTopContext)
56+
if (!context) {
57+
throw new Error('useModalBottomToTop must be used within a ModalBottomToTopProvider')
58+
}
59+
return context
60+
}
61+
62+
// Optional hook that doesn't throw if no provider exists
63+
export const useModalBottomToTopOptional = () => {
64+
return useContext(ModalBottomToTopContext)
65+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export { ModalBottomToTop } from './ModalBottomToTop'
2+
export {
3+
ModalBottomToTopProvider,
4+
useModalBottomToTop,
5+
useModalBottomToTopOptional
6+
} from './ModalBottomToTopContext'

0 commit comments

Comments
 (0)