Co-authored-by: lethemanh <lethemanh@lethemanhs-MacBook-Pro.local>
This commit is contained in:
@@ -10,34 +10,23 @@ import {
|
|||||||
AccordionDetails,
|
AccordionDetails,
|
||||||
AccordionSummary,
|
AccordionSummary,
|
||||||
Checkbox,
|
Checkbox,
|
||||||
Divider,
|
|
||||||
IconButton,
|
IconButton,
|
||||||
ListItem,
|
ListItem
|
||||||
Menu,
|
|
||||||
MenuItem
|
|
||||||
} from '@linagora/twake-mui'
|
} from '@linagora/twake-mui'
|
||||||
import AddIcon from '@mui/icons-material/Add'
|
import AddIcon from '@mui/icons-material/Add'
|
||||||
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
|
import ExpandMoreIcon from '@mui/icons-material/ExpandMore'
|
||||||
import MoreHorizIcon from '@mui/icons-material/MoreHoriz'
|
import MoreHorizIcon from '@mui/icons-material/MoreHoriz'
|
||||||
import { SetStateAction, useEffect, useMemo, useState } from 'react'
|
import { SetStateAction, useEffect, useMemo, useState, useRef } from 'react'
|
||||||
import { useI18n } from 'twake-i18n'
|
import { useI18n } from 'twake-i18n'
|
||||||
|
import { useScreenSizeDetection } from '@/useScreenSizeDetection'
|
||||||
import CalendarPopover from './CalendarModal'
|
import CalendarPopover from './CalendarModal'
|
||||||
import CalendarSearch from './CalendarSearch'
|
import CalendarSearch from './CalendarSearch'
|
||||||
import { DeleteCalendarDialog } from './DeleteCalendarDialog'
|
import { DeleteCalendarDialog } from './DeleteCalendarDialog'
|
||||||
import { OwnerCaption } from './OwnerCaption'
|
import { OwnerCaption } from './OwnerCaption'
|
||||||
import CalendarResources from './CalendarResources'
|
import CalendarResources from './CalendarResources'
|
||||||
|
import { CalendarSelectorMenu } from './CalendarSelectorMenu'
|
||||||
|
|
||||||
function CalendarAccordion({
|
const CalendarAccordion: React.FC<{
|
||||||
title,
|
|
||||||
calendars,
|
|
||||||
selectedCalendars,
|
|
||||||
handleToggle,
|
|
||||||
showAddButton = false,
|
|
||||||
onAddClick,
|
|
||||||
defaultExpanded = false,
|
|
||||||
setOpen,
|
|
||||||
hideOwner
|
|
||||||
}: {
|
|
||||||
title: string
|
title: string
|
||||||
calendars: string[]
|
calendars: string[]
|
||||||
selectedCalendars: string[]
|
selectedCalendars: string[]
|
||||||
@@ -47,14 +36,24 @@ function CalendarAccordion({
|
|||||||
defaultExpanded?: boolean
|
defaultExpanded?: boolean
|
||||||
setOpen: (id: string) => void
|
setOpen: (id: string) => void
|
||||||
hideOwner?: boolean
|
hideOwner?: boolean
|
||||||
}) {
|
}> = ({
|
||||||
|
title,
|
||||||
|
calendars,
|
||||||
|
selectedCalendars,
|
||||||
|
handleToggle,
|
||||||
|
showAddButton = false,
|
||||||
|
onAddClick,
|
||||||
|
defaultExpanded = false,
|
||||||
|
setOpen,
|
||||||
|
hideOwner
|
||||||
|
}) => {
|
||||||
const allCalendars = useAppSelector(state => state.calendars.list)
|
const allCalendars = useAppSelector(state => state.calendars.list)
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
|
|
||||||
const [expended, setExpended] = useState(defaultExpanded)
|
const [expended, setExpended] = useState(defaultExpanded)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handleExpendedChange = () => {
|
const handleExpendedChange = (): void => {
|
||||||
setExpended(defaultExpanded)
|
setExpended(defaultExpanded)
|
||||||
}
|
}
|
||||||
handleExpendedChange()
|
handleExpendedChange()
|
||||||
@@ -127,13 +126,10 @@ function CalendarAccordion({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function CalendarSelection({
|
const CalendarSelection: React.FC<{
|
||||||
selectedCalendars,
|
|
||||||
setSelectedCalendars
|
|
||||||
}: {
|
|
||||||
selectedCalendars: string[]
|
selectedCalendars: string[]
|
||||||
setSelectedCalendars: (value: SetStateAction<string[]>) => void
|
setSelectedCalendars: (value: SetStateAction<string[]>) => void
|
||||||
}) {
|
}> = ({ selectedCalendars, setSelectedCalendars }) => {
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const userId = useAppSelector(state => state.user.userData?.openpaasId) ?? ''
|
const userId = useAppSelector(state => state.user.userData?.openpaasId) ?? ''
|
||||||
const calendars = useAppSelector(state => state.calendars.list)
|
const calendars = useAppSelector(state => state.calendars.list)
|
||||||
@@ -158,7 +154,7 @@ export default function CalendarSelection({
|
|||||||
extractEventBaseUuid(id) !== userId && calendars?.[id]?.owner?.resource
|
extractEventBaseUuid(id) !== userId && calendars?.[id]?.owner?.resource
|
||||||
)
|
)
|
||||||
|
|
||||||
const handleCalendarToggle = (name: string) => {
|
const handleCalendarToggle = (name: string): void => {
|
||||||
setSelectedCalendars((prev: string[]) =>
|
setSelectedCalendars((prev: string[]) =>
|
||||||
prev.includes(name) ? prev.filter(n => n !== name) : [...prev, name]
|
prev.includes(name) ? prev.filter(n => n !== name) : [...prev, name]
|
||||||
)
|
)
|
||||||
@@ -243,7 +239,7 @@ export default function CalendarSelection({
|
|||||||
/>
|
/>
|
||||||
<CalendarSearch
|
<CalendarSearch
|
||||||
open={Boolean(anchorElCalOthers)}
|
open={Boolean(anchorElCalOthers)}
|
||||||
onClose={(newCalIds?: string[]) => {
|
onClose={(newCalIds?: string[] | Record<string, never>) => {
|
||||||
setAnchorElCalOthers(null)
|
setAnchorElCalOthers(null)
|
||||||
if (newCalIds?.length) {
|
if (newCalIds?.length) {
|
||||||
newCalIds.forEach(id => handleCalendarToggle(id))
|
newCalIds.forEach(id => handleCalendarToggle(id))
|
||||||
@@ -265,15 +261,7 @@ export default function CalendarSelection({
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function CalendarSelector({
|
const CalendarSelector: React.FC<{
|
||||||
calendars,
|
|
||||||
id,
|
|
||||||
isPersonal,
|
|
||||||
selectedCalendars,
|
|
||||||
handleCalendarToggle,
|
|
||||||
setOpen,
|
|
||||||
hideOwner
|
|
||||||
}: {
|
|
||||||
calendars: Record<string, Calendar>
|
calendars: Record<string, Calendar>
|
||||||
id: string
|
id: string
|
||||||
isPersonal: boolean
|
isPersonal: boolean
|
||||||
@@ -281,25 +269,62 @@ function CalendarSelector({
|
|||||||
handleCalendarToggle: (name: string) => void
|
handleCalendarToggle: (name: string) => void
|
||||||
setOpen: () => void
|
setOpen: () => void
|
||||||
hideOwner?: boolean
|
hideOwner?: boolean
|
||||||
}) {
|
}> = ({
|
||||||
|
calendars,
|
||||||
|
id,
|
||||||
|
isPersonal,
|
||||||
|
selectedCalendars,
|
||||||
|
handleCalendarToggle,
|
||||||
|
setOpen,
|
||||||
|
hideOwner
|
||||||
|
}) => {
|
||||||
const { t } = useI18n()
|
const { t } = useI18n()
|
||||||
const dispatch = useAppDispatch()
|
const dispatch = useAppDispatch()
|
||||||
const calLink = useAppSelector(state => state.calendars.list[id].link) ?? ''
|
const calLink = useAppSelector(state => state.calendars.list[id].link) ?? ''
|
||||||
|
const { isTooSmall: isMobile } = useScreenSizeDetection()
|
||||||
|
|
||||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
|
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null)
|
||||||
const open = Boolean(anchorEl)
|
const open = Boolean(anchorEl)
|
||||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
|
||||||
|
const handleClick = (event: React.MouseEvent<HTMLButtonElement>): void => {
|
||||||
setAnchorEl(event.currentTarget)
|
setAnchorEl(event.currentTarget)
|
||||||
}
|
}
|
||||||
const handleClose = () => {
|
const handleClose = (): void => {
|
||||||
setAnchorEl(null)
|
setAnchorEl(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const longPressTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
|
||||||
|
const isLongPressedRef = useRef(false)
|
||||||
|
|
||||||
|
const handleTouchStart = (): void => {
|
||||||
|
if (!isMobile) return
|
||||||
|
isLongPressedRef.current = false
|
||||||
|
longPressTimerRef.current = setTimeout(() => {
|
||||||
|
isLongPressedRef.current = true
|
||||||
|
setAnchorEl(document.body)
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTouchEnd = (): void => {
|
||||||
|
if (longPressTimerRef.current) {
|
||||||
|
clearTimeout(longPressTimerRef.current)
|
||||||
|
longPressTimerRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleTouchMove = (): void => {
|
||||||
|
if (longPressTimerRef.current) {
|
||||||
|
clearTimeout(longPressTimerRef.current)
|
||||||
|
longPressTimerRef.current = null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const [userId, calId] = id.split('/')
|
const [userId, calId] = id.split('/')
|
||||||
const isDefault = isPersonal && userId === calId
|
const isDefault = isPersonal && userId === calId
|
||||||
|
|
||||||
const [deletePopupOpen, setDeletePopupOpen] = useState(false)
|
const [deletePopupOpen, setDeletePopupOpen] = useState(false)
|
||||||
const handleDeleteConfirm = () => {
|
const handleDeleteConfirm = async (): Promise<void> => {
|
||||||
dispatch(removeCalendarAsync({ calId: id, calLink }))
|
await dispatch(removeCalendarAsync({ calId: id, calLink }))
|
||||||
setDeletePopupOpen(false)
|
setDeletePopupOpen(false)
|
||||||
handleClose()
|
handleClose()
|
||||||
}
|
}
|
||||||
@@ -339,6 +364,15 @@ function CalendarSelector({
|
|||||||
'& .MoreBtn': { opacity: 1 }
|
'& .MoreBtn': { opacity: 1 }
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
onTouchStart={handleTouchStart}
|
||||||
|
onTouchEnd={handleTouchEnd}
|
||||||
|
onTouchMove={handleTouchMove}
|
||||||
|
onClickCapture={e => {
|
||||||
|
if (isLongPressedRef.current) {
|
||||||
|
e.stopPropagation()
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<label
|
<label
|
||||||
style={{
|
style={{
|
||||||
@@ -381,26 +415,23 @@ function CalendarSelector({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</label>
|
</label>
|
||||||
<IconButton className="MoreBtn" onClick={handleClick}>
|
{!isMobile && (
|
||||||
<MoreHorizIcon />
|
<IconButton className="MoreBtn" onClick={handleClick}>
|
||||||
</IconButton>
|
<MoreHorizIcon />
|
||||||
</ListItem>
|
</IconButton>
|
||||||
<Menu id={id} anchorEl={anchorEl} open={open} onClose={handleClose}>
|
|
||||||
<MenuItem
|
|
||||||
onClick={() => {
|
|
||||||
setOpen()
|
|
||||||
handleClose()
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{t('actions.modify')}
|
|
||||||
</MenuItem>
|
|
||||||
{!isDefault && <Divider />}
|
|
||||||
{!isDefault && (
|
|
||||||
<MenuItem onClick={() => setDeletePopupOpen(!deletePopupOpen)}>
|
|
||||||
{isPersonal ? t('actions.delete') : t('actions.remove')}
|
|
||||||
</MenuItem>
|
|
||||||
)}
|
)}
|
||||||
</Menu>
|
</ListItem>
|
||||||
|
|
||||||
|
<CalendarSelectorMenu
|
||||||
|
id={id}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={open}
|
||||||
|
onClose={handleClose}
|
||||||
|
onModify={setOpen}
|
||||||
|
onDelete={() => setDeletePopupOpen(true)}
|
||||||
|
isDefault={isDefault}
|
||||||
|
isPersonal={isPersonal}
|
||||||
|
/>
|
||||||
|
|
||||||
<DeleteCalendarDialog
|
<DeleteCalendarDialog
|
||||||
deletePopupOpen={deletePopupOpen}
|
deletePopupOpen={deletePopupOpen}
|
||||||
@@ -408,8 +439,10 @@ function CalendarSelector({
|
|||||||
calendars={calendars}
|
calendars={calendars}
|
||||||
id={id}
|
id={id}
|
||||||
isPersonal={isPersonal}
|
isPersonal={isPersonal}
|
||||||
handleDeleteConfirm={handleDeleteConfirm}
|
handleDeleteConfirm={() => void handleDeleteConfirm()}
|
||||||
/>
|
/>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default CalendarSelection
|
||||||
|
|||||||
@@ -0,0 +1,53 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { Divider, Menu, MenuItem } from '@linagora/twake-mui'
|
||||||
|
import { useI18n } from 'twake-i18n'
|
||||||
|
|
||||||
|
interface CalendarSelectorDesktopMenuProps {
|
||||||
|
id: string
|
||||||
|
anchorEl: HTMLElement | null
|
||||||
|
open: boolean
|
||||||
|
onClose: () => void
|
||||||
|
onModify: () => void
|
||||||
|
onDelete: () => void
|
||||||
|
isDefault: boolean
|
||||||
|
isPersonal: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CalendarSelectorDesktopMenu: React.FC<
|
||||||
|
CalendarSelectorDesktopMenuProps
|
||||||
|
> = ({
|
||||||
|
id,
|
||||||
|
anchorEl,
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
onModify,
|
||||||
|
onDelete,
|
||||||
|
isDefault,
|
||||||
|
isPersonal
|
||||||
|
}) => {
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Menu id={id} anchorEl={anchorEl} open={open} onClose={onClose}>
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
onModify()
|
||||||
|
onClose()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{t('actions.modify')}
|
||||||
|
</MenuItem>
|
||||||
|
{!isDefault && <Divider />}
|
||||||
|
{!isDefault && (
|
||||||
|
<MenuItem
|
||||||
|
onClick={() => {
|
||||||
|
onDelete()
|
||||||
|
onClose()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{isPersonal ? t('actions.delete') : t('actions.remove')}
|
||||||
|
</MenuItem>
|
||||||
|
)}
|
||||||
|
</Menu>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import {
|
||||||
|
styled,
|
||||||
|
SwipeableDrawer,
|
||||||
|
List,
|
||||||
|
ListItemButton,
|
||||||
|
ListItemText
|
||||||
|
} from '@linagora/twake-mui'
|
||||||
|
import { useI18n } from 'twake-i18n'
|
||||||
|
|
||||||
|
const StyledSwipeableDrawer = styled(SwipeableDrawer)(({ theme }) => ({
|
||||||
|
zIndex: theme.zIndex.modal + 100
|
||||||
|
}))
|
||||||
|
|
||||||
|
interface CalendarSelectorMobileMenuProps {
|
||||||
|
open: boolean
|
||||||
|
onClose: () => void
|
||||||
|
onModify: () => void
|
||||||
|
onDelete: () => void
|
||||||
|
isDefault: boolean
|
||||||
|
isPersonal: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CalendarSelectorMobileMenu: React.FC<
|
||||||
|
CalendarSelectorMobileMenuProps
|
||||||
|
> = ({ open, onClose, onModify, onDelete, isDefault, isPersonal }) => {
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledSwipeableDrawer
|
||||||
|
anchor="bottom"
|
||||||
|
open={open}
|
||||||
|
onClose={onClose}
|
||||||
|
onOpen={() => {}}
|
||||||
|
disableAutoFocus
|
||||||
|
>
|
||||||
|
<List>
|
||||||
|
<ListItemButton
|
||||||
|
onClick={() => {
|
||||||
|
onModify()
|
||||||
|
onClose()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ListItemText primary={t('actions.modify')} />
|
||||||
|
</ListItemButton>
|
||||||
|
{!isDefault && (
|
||||||
|
<ListItemButton
|
||||||
|
onClick={() => {
|
||||||
|
onDelete()
|
||||||
|
onClose()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ListItemText
|
||||||
|
primary={isPersonal ? t('actions.delete') : t('actions.remove')}
|
||||||
|
slotProps={{
|
||||||
|
primary: {
|
||||||
|
color: 'error.main'
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</ListItemButton>
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
</StyledSwipeableDrawer>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { useScreenSizeDetection } from '@/useScreenSizeDetection'
|
||||||
|
import { CalendarSelectorDesktopMenu } from './CalendarSelectorDesktopMenu'
|
||||||
|
import { CalendarSelectorMobileMenu } from './CalendarSelectorMobileMenu'
|
||||||
|
|
||||||
|
interface CalendarSelectorMenuProps {
|
||||||
|
id: string
|
||||||
|
anchorEl: HTMLElement | null
|
||||||
|
open: boolean
|
||||||
|
onClose: () => void
|
||||||
|
onModify: () => void
|
||||||
|
onDelete: () => void
|
||||||
|
isDefault: boolean
|
||||||
|
isPersonal: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CalendarSelectorMenu: React.FC<CalendarSelectorMenuProps> = ({
|
||||||
|
id,
|
||||||
|
anchorEl,
|
||||||
|
open,
|
||||||
|
onClose,
|
||||||
|
onModify,
|
||||||
|
onDelete,
|
||||||
|
isDefault,
|
||||||
|
isPersonal
|
||||||
|
}) => {
|
||||||
|
const { isTooSmall: isMobile } = useScreenSizeDetection()
|
||||||
|
|
||||||
|
if (!isMobile) {
|
||||||
|
return (
|
||||||
|
<CalendarSelectorDesktopMenu
|
||||||
|
id={id}
|
||||||
|
anchorEl={anchorEl}
|
||||||
|
open={open}
|
||||||
|
onClose={onClose}
|
||||||
|
onModify={onModify}
|
||||||
|
onDelete={onDelete}
|
||||||
|
isDefault={isDefault}
|
||||||
|
isPersonal={isPersonal}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CalendarSelectorMobileMenu
|
||||||
|
open={open}
|
||||||
|
onClose={onClose}
|
||||||
|
onModify={onModify}
|
||||||
|
onDelete={onDelete}
|
||||||
|
isDefault={isDefault}
|
||||||
|
isPersonal={isPersonal}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user