import { Box, Drawer, Toolbar } from '@mui/material'
import React from 'react'
import Header from '../components/Header'
import ChannelMenu from '../components/ChannelMenu'
export default function Main() {
return (
<>
{/* TODO backgroundColor 테마 적용 */}
<Box sx={{ display: 'flex', backgroundColor: 'white' }}>
<Header />
<Drawer variant="permanent" sx={{ width: 300 }} className="no-scroll">
<Toolbar />
<Box sx={{ display: 'flex', minHeight: 'calc(100vh-64px)' }}>
<ChannelMenu />
</Box>
</Drawer>
</Box>
</>
)
}
src/components/ChannelMenu.jsx
import {
Dialog,
DialogContentText,
DialogTitle,
IconButton,
List,
ListItem,
DialogContent,
ListItemIcon,
ListItemText,
TextField,
DialogActions,
Button,
} from '@mui/material'
import React, { useCallback, useEffect, useState } from 'react'
import AddIcon from '@mui/icons-material/Add'
import ArrowDropDown from '@mui/icons-material/ArrowDropDown'
import '../firebase'
import {
child,
ref,
push,
getDatabase,
update,
onChildAdded,
} from 'firebase/database'
import { useDispatch } from 'react-redux'
import { setCurrentChannel } from '../store/channelReducer'
export default function ChannelMenu() {
// 채널 생성시 모달 오픈
const [open, setOpen] = useState(false)
// 채널명
const [channelName, setChannelName] = useState('')
// 채널 설명
const [channelDescription, setChannelDescription] = useState('')
// 채널 목록
const [channels, setChannels] = useState([])
// 활성화된 채널ID
const [activeChannelId, setActiveChannelId] = useState('')
// 첫 로드
const [firstLoaded, setFirstLoaded] = useState(true)
// redux dispatch
const dispatch = useDispatch()
// 활성화된 채널 변경하기
const changeChannel = channel => {
setActiveChannelId(channel.id) //channel로 활성화
dispatch(setCurrentChannel(channel)) //전역 store에 저장
}
// 모달 오픈
const handleClickOpen = () => {
setOpen(true)
}
// 모달 닫기
const handleClickClose = () => {
setOpen(false)
}
// 채널 목록 저장하기
useEffect(() => {
const db = getDatabase()
const unsubscribe = onChildAdded(ref(db, 'channels'), snapshot => {
setChannels(channelArr => [...channelArr, snapshot.val()])
})
return () => {
setChannels([])
unsubscribe()
}
}, [])
// 채널 생성
const handleSubmit = useCallback(async () => {
const db = getDatabase() // 데이터베이스 가져오기 (읽기 쓰기를 위함.)
const key = push(child(ref(db), 'chennels')).key // 키 생성
// 새로운 채널
const newChannel = {
id: key,
name: channelName,
details: channelDescription,
}
// 업데이트할 채널 생성
const updates = {}
updates['/channels/' + key] = newChannel
// firebase에 업데이트
try {
await update(ref(db), updates)
setChannelName('')
setChannelDescription('')
handleClickClose()
} catch (error) {
console.error(error)
}
}, [channelDescription, channelName])
// 처음 로딩시에만 첫번째 채널로 활성화
useEffect(() => {
if (channels.length > 0 && firstLoaded) {
setActiveChannelId(channels[0].id)
dispatch(setCurrentChannel(channels[0]))
setFirstLoaded(false)
}
}, [channels, firstLoaded, dispatch])
return (
<>
<List sx={{ overflow: 'auto', width: 240, backgroundColor: '#4c3c4d' }}>
<ListItem
secondaryAction={
<IconButton sx={{ color: '#9a939b' }} onClick={handleClickOpen}>
<AddIcon />
</IconButton>
}
>
<ListItemIcon sx={{ color: '#9a939b' }}>
<ArrowDropDown />
</ListItemIcon>
<ListItemText
primary="채널"
sx={{ wordBreak: 'break-all', color: '#9a939b' }}
/>
</ListItem>
<List component="div" disablePadding sx={{ pl: 3 }}>
{/* TODO store 구현, selected 구현 */}
{channels.map(channel => (
<ListItem
selected={channel.id === activeChannelId}
onClick={() => changeChannel(channel)}
button
key={channel.id}
>
<ListItemText
primary={`# ${channel.name}`}
sx={{ wordBreak: 'break-all', color: '#918890' }}
/>
</ListItem>
))}
</List>
</List>
<Dialog open={open} onClose={handleClickClose}>
<DialogTitle>채널 추가</DialogTitle>
<DialogContent>
<DialogContentText>
생성할 채널명과 설명을 입력해주세요.
</DialogContentText>
<TextField
autoFocus
margin="dense"
label="채널명"
type="text"
fullWidth
variant="standard"
onChange={e => setChannelName(e.target.value)}
/>
<TextField
margin="dense"
label="설명"
type="text"
fullWidth
variant="standard"
onChange={e => setChannelDescription(e.target.value)}
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClickClose}>취소</Button>
<Button onClick={handleSubmit}>생성</Button>
</DialogActions>
</Dialog>
</>
)
}
src/stroe/channelReducer.js 생성
// 액션 타입
const SET_CURRENT_CHANNEL = 'SET_CURRENT_CHANNEL'
// 액션 생성 함수
export const setCurrentChannel = channel => ({
type: SET_CURRENT_CHANNEL,
currentChannel: channel,
})
// initial state
const initialState = { currentChannel: null }
// reducer
const channelReducer = (state = initialState, action) => {
switch (action.type) {
case SET_CURRENT_CHANNEL:
return {
currentChannel: action.currentChannel,
}
default:
return state
}
}
export default channelReducer
npm i redux-devtools-extension