Skip to content

Commit

Permalink
Add more apis to fetch agenda and display them
Browse files Browse the repository at this point in the history
  • Loading branch information
vorasudh committed Oct 1, 2024
1 parent 01a143e commit 13c61e1
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 99 deletions.
80 changes: 80 additions & 0 deletions frontend/src/components/AgendaDrawer/AgendaDrawer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import React, { useEffect, useState } from "react";
import {
Drawer,
IconButton,
List,
ListItem,
ListItemText,
Typography,
useMediaQuery,
useTheme,
} from "@mui/material";
import FormatListBulletedIcon from "@mui/icons-material/FormatListBulleted";
import { useAgenda } from "../../utils/meetingAgenda";


export const AgendaDrawer: React.FC = () => {
const [isOpen, setIsOpen] = useState(false);
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));

const { agendaItems } = useAgenda();

const toggleDrawer = (open: boolean) => (event: React.KeyboardEvent | React.MouseEvent) => {
if (
event.type === "keydown" &&
((event as React.KeyboardEvent).key === "Tab" || (event as React.KeyboardEvent).key === "Shift")
) {
return;
}
setIsOpen(open);
};

useEffect(() => {
if (agendaItems.length > 0 && !isMobile) {
setIsOpen(true);
}
}, [agendaItems]);

const drawerContent = (
<List>
<Typography variant="h6" sx={{ p: 2 }}>
Agenda
</Typography>
{agendaItems.map((item, index) => (
<ListItem key={index}>
<ListItemText primary={item} />
</ListItem>
))}
</List>
);

return (
<>
{isMobile && (
<IconButton
onClick={toggleDrawer(true)}
sx={{ position: "fixed", right: 16, top: 16, zIndex: 1100 }}
>
<FormatListBulletedIcon />
</IconButton>
)}
<Drawer
anchor="right"
open={isMobile ? isOpen : true}
onClose={toggleDrawer(false)}
variant={isMobile ? "temporary" : "permanent"}
sx={{
width: 150,
flexShrink: 0,
"& .MuiDrawer-paper": {
width: 150,
boxSizing: "border-box",
},
}}
>
{drawerContent}
</Drawer>
</>
);
};
2 changes: 1 addition & 1 deletion frontend/src/components/MeetingsDrawer/MeetingsDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import {
import HomeIcon from '@mui/icons-material/Home'
import MeetingRoomIcon from '@mui/icons-material/MeetingRoom'

import './Drawer.css'
import './MeetingsDrawer.css'

const fetchMeetings = async () => {
const response = await fetch('https://codefusion.lholz.de/meetings/?skip=0&limit=100')
Expand Down
154 changes: 80 additions & 74 deletions frontend/src/container/Meeting/Meeting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import SmartToyIcon from '@mui/icons-material/SmartToy';

import './Meeting.css';
import { useUser } from '../../utils/userProvider';
import { AgendaDrawer } from '../../components/AgendaDrawer/AgendaDrawer';
import { useAgenda } from '../../utils/meetingAgenda';

const deleteConversation = async ({ meetingId, userId }) => {
const response = await fetch(`https://codefusion.lholz.de/meetings/${meetingId}/${userId}/conversation`, {
Expand Down Expand Up @@ -59,6 +61,7 @@ const sendMessage = async ({ message, meetingId, userId }) => {
export const Meeting = () => {
const { id: meetingId } = useParams();
const { userId } = useUser();
const { agendaItems, setAgendaItems } = useAgenda();
const navigate = useNavigate();

const [messages, setMessages] = useState([]);
Expand Down Expand Up @@ -99,6 +102,7 @@ export const Meeting = () => {
mutationFn: sendMessage,
onSuccess: (data) => {
setMessages(() => data.chat_messages);
setAgendaItems(data.agenda_items);

if (data.finished) {
navigate(`/meeting/${meetingId}/agenda`);
Expand Down Expand Up @@ -126,87 +130,89 @@ export const Meeting = () => {
};

return (
<Box className="MeetingContainer">
<Typography variant="h4" gutterBottom>
Meeting: {meetingId}
</Typography>
<div className="ChatContainer">
<List>
{messages.map((message, index) => (
<ListItem
key={index}
sx={{
display: 'flex',
justifyContent: message.author !== 'assistant' ? 'flex-end' : 'flex-start',
mb: 2,
}}
className="MessageItem"
>
<Box
<>
<Box className="MeetingContainer">
<Typography variant="h4" gutterBottom>
Meeting: {meetingId}
</Typography>
<div className="ChatContainer">
<List>
{messages.map((message, index) => (
<ListItem
key={index}
sx={{
display: 'flex',
flexDirection: message.author !== 'assistant' ? 'row-reverse' : 'row',
alignItems: 'center',
justifyContent: message.author !== 'assistant' ? 'flex-end' : 'flex-start',
mb: 2,
}}
className="MessageItem"
>
<Avatar sx={{ bgcolor: message.author !== 'assistant' ? 'primary.main' : 'secondary.main', mr: message.author !== 'assistant' ? 0 : 1, ml: message.author !== 'assistant' ? 1 : 0 }}>
{message.author !== 'assistant' ? <PersonIcon /> : <SmartToyIcon />}
</Avatar>
<Paper
elevation={3}
<Box
sx={{
p: 2,
bgcolor: message.author !== 'assistant' ? 'primary.light' : 'secondary.light',
maxWidth: '70%',
borderRadius: 4,
borderTopRightRadius: message.author !== 'assistant' ? 0 : 16,
borderTopLeftRadius: message.author !== 'assistant' ? 16 : 0,
wordBreak: 'break-word',
whiteSpace: 'pre-wrap',
display: 'flex',
flexDirection: message.author !== 'assistant' ? 'row-reverse' : 'row',
alignItems: 'center',
}}
>
<Typography variant="body1">{message.message}</Typography>
</Paper>
</Box>
</ListItem>
))}
<div ref={messagesEndRef} />
</List>
<Button
variant="outlined"
color="secondary"
onClick={handleDeleteConversation}
disabled={deleteMutation.isPending}
sx={{ ml: 1 }}
>
{deleteMutation.isPending ? 'Clearing...' : 'Clear Conversation'}
</Button>
</div>
<Box sx={{ display: 'flex', mb: 2 }}>
<TextField
fullWidth
autoFocus
variant="outlined"
placeholder="Type your message..."
value={inputMessage}
onChange={(e) => setInputMessage(e.target.value)}
onKeyPress={(e) => {
if (e.key === 'Enter') {
handleSendMessage();
}
}}
/>
<Button
variant="contained"
color="primary"
endIcon={<SendIcon />}
onClick={handleSendMessage}
disabled={mutation.isPending}
sx={{ ml: 1 }}
>
{mutation.isPending ? 'Sending...' : 'Send'}
</Button>
<Avatar sx={{ bgcolor: message.author !== 'assistant' ? 'primary.main' : 'secondary.main', mr: message.author !== 'assistant' ? 0 : 1, ml: message.author !== 'assistant' ? 1 : 0 }}>
{message.author !== 'assistant' ? <PersonIcon /> : <SmartToyIcon />}
</Avatar>
<Paper
elevation={3}
sx={{
p: 2,
bgcolor: message.author !== 'assistant' ? 'primary.light' : 'secondary.light',
maxWidth: '70%',
borderRadius: 4,
borderTopRightRadius: message.author !== 'assistant' ? 0 : 16,
borderTopLeftRadius: message.author !== 'assistant' ? 16 : 0,
wordBreak: 'break-word',
whiteSpace: 'pre-wrap',
}}
>
<Typography variant="body1">{message.message}</Typography>
</Paper>
</Box>
</ListItem>
))}
<div ref={messagesEndRef} />
</List>
<Button
variant="outlined"
color="secondary"
onClick={handleDeleteConversation}
disabled={deleteMutation.isPending}
sx={{ ml: 1 }}
>
{deleteMutation.isPending ? 'Clearing...' : 'Clear Conversation'}
</Button>
</div>
<Box sx={{ display: 'flex', mb: 2 }}>
<TextField
fullWidth
autoFocus
variant="outlined"
placeholder="Type your message..."
value={inputMessage}
onChange={(e) => setInputMessage(e.target.value)}
onKeyPress={(e) => {
if (e.key === 'Enter') {
handleSendMessage();
}
}}
/>
<Button
variant="contained"
color="primary"
endIcon={<SendIcon />}
onClick={handleSendMessage}
disabled={mutation.isPending}
sx={{ ml: 1 }}
>
{mutation.isPending ? 'Sending...' : 'Send'}
</Button>
</Box>
</Box>
</Box>
</>
);
};
9 changes: 6 additions & 3 deletions frontend/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { PrepNow } from './container/PrepNow/PrepNow'
import AgendaList from './container/AgendaList/AgendaList'
import MeetingRoot from './container/Meeting/MeetingRoot'
import { UserProvider } from './utils/userProvider'
import { AgendaProvider } from './utils/meetingAgenda'

const queryClient = new QueryClient()

Expand Down Expand Up @@ -68,9 +69,11 @@ root.render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<ThemeProvider theme={theme}>
<UserProvider>
<RouterProvider router={router} />
</UserProvider>
<UserProvider>
<AgendaProvider>
<RouterProvider router={router} />
</AgendaProvider>
</UserProvider>
</ThemeProvider>
</QueryClientProvider>
</React.StrictMode>
Expand Down
30 changes: 30 additions & 0 deletions frontend/src/utils/meetingAgenda.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { createContext, useState, useContext, ReactNode } from 'react';

interface AgendaContextType {
agendaItems: string[];
setAgendaItems: React.Dispatch<React.SetStateAction<string[]>>;
}

const AgendaContext = createContext<AgendaContextType | undefined>(undefined);

interface AgendaProviderProps {
children: ReactNode;
}

export const AgendaProvider: React.FC<AgendaProviderProps> = ({ children }) => {
const [agendaItems, setAgendaItems] = useState<string[]>([]);

return (
<AgendaContext.Provider value={{ agendaItems, setAgendaItems }}>
{children}
</AgendaContext.Provider>
);
};

export const useAgenda = (): AgendaContextType => {
const context = useContext(AgendaContext);
if (context === undefined) {
throw new Error('useAgenda must be used within an AgendaProvider');
}
return context;
};
21 changes: 0 additions & 21 deletions frontend/src/utils/userProvider.jsx

This file was deleted.

30 changes: 30 additions & 0 deletions frontend/src/utils/userProvider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { createContext, useState, useContext, ReactNode } from 'react';

interface UserContextType {
userId: number;
setUserId: React.Dispatch<React.SetStateAction<number>>;
}

interface UserProviderProps {
children: ReactNode;
}

const UserContext = createContext<UserContextType | undefined>(undefined);

export const UserProvider = ({ children }: UserProviderProps) => {
const [userId, setUserId] = useState(2);

return (
<UserContext.Provider value={{ userId, setUserId }}>
{children}
</UserContext.Provider>
);
};

export const useUser = (): UserContextType => {
const context = useContext(UserContext);
if (context === undefined) {
throw new Error('useUser must be used within a UserProvider');
}
return context;
};

0 comments on commit 13c61e1

Please sign in to comment.