Calendar App
React, Redux, MongoDB, Node, Express, Bootstrap, ViteDescription
Fully functional and fullstack calendar App.
- Includes Login page for Auth, React-big-calendar- React-date-picker- Middlewares- Form Auth
- Authentication handled with JWT.
- Redux for state management.
- MongoDB
Key takeaways
This is a complex project both in the backend and frontend. Besides all route and controller logic with authentication, CRUD and so on in the backend, my main takeaway for this project is the state management with Redux in the frontend which is depicted in the diagram below.
Store
Combines all reducers and apply async-await fuction in replace of Thunks (middleware that allows you to return functions).
View code
1export const calendarSlice = createSlice({ 2 name: "calendar", 3 initialState: { 4 isLoadingEvents: true, 5 events: [ 6 //tempEvent 7 ], 8 activeEvent: null, 9 }, 10 reducers: { 11 onSetActiveEvent: (state, { payload }) => { 12 state.activeEvent = payload; 13 }, 14 onAddNewEvent: (state, { payload }) => { 15 state.events.push(payload); 16 state.activeEvent = null; 17 }, 18 onUpdateEvent: (state, { payload }) => { 19 state.events = state.events.map((event) => { 20 if (event.id === payload.id) { 21 return payload; 22 } 23 return event; 24 }); 25 }, 26 onDeleteEvent: (state) => { 27 if (state.activeEvent) { 28 state.events = state.events.filter( 29 (event) => event.id !== state.activeEvent.id 30 ); 31 state.activeEvent = null; 32 } 33 }, 34 35 onLoadEvents: (state, { payload = [] }) => { 36 state.isLoadingEvents = false; 37 //state.events = payload; 38 payload.forEach((event) => { 39 const exists = state.events.some((dbEvent) => dbEvent.id === event.id); 40 if (!exists) { 41 state.events.push(event); 42 } 43 }); 44 }, 45 onLogoutCalendar: (state) => { 46 (state.isLoadingEvents = true), (state.events = []); 47 state.activeEvent = null; 48 }, 49 }, 50}); 51 52export const { 53 onSetActiveEvent, 54 onAddNewEvent, 55 onUpdateEvent, 56 onDeleteEvent, 57 onLoadEvents, 58 onLogoutCalendar, 59} = calendarSlice.actions; 60
Components
This is the look of the composition of the calendar App.
View code
1export const CalendarPage = () => { 2 3 const { user } = useAuthStore(); 4 const { openDateModal } = useUiStore (); 5 const { events, setActiveEvent, startLoadingEvents } = useCalendarStore(); 6 7 const[lastView, setLastView] = useState(localStorage.getItem('lastView') || 'week'); 8 9 const eventStyleGetter = ( event, start, end, isSelected ) => { 10 11 //console.log(event); 12 13 const isMyEvent = ( user.uid === event.user._id ) || ( user.uid === event.user._id); 14 15 const style = { 16 backgroundColor: isMyEvent ? '#347CF7' : '#465660', 17 borderRadius: '0px', 18 opacity: 0.8, 19 color: 'white' 20 } 21 22 return { 23 style 24 } 25 } 26 27 const onDoubleClick = ( event ) => { 28 // console.log( {doubleClick: event }); 29 openDateModal(); 30 } 31 32 const onSelect = ( event ) => { 33 //console.log( {click: event }); 34 setActiveEvent( event ); 35 } 36 37 const onViewChanged = ( event ) => { 38 localStorage.setItem('lastView', event ); 39 setLastView( event ) 40 } 41 42 useEffect(() => { 43 startLoadingEvents() 44 }, []) 45 46 return ( 47 <> 48 <Navbar /> 49 50 <Calendar 51 culture='es' 52 localizer={localizer} 53 events={events} 54 formats 55 defaultView= { lastView } 56 startAccessor="start" 57 endAccessor="end" 58 style={{ height: 'calc( 100vh - 80px )' }} 59 messages={ getMessagesES() } 60 eventPropGetter= { eventStyleGetter } 61 components= {{ 62 event: CalendarEvent 63 }} 64 onDoubleClickEvent = { onDoubleClick } 65 onSelectEvent = { onSelect} 66 onView = {onViewChanged} 67 68 /> 69 70 <CalendarModal /> 71 <FabAddNew /> 72 <FabDelete /> 73 74 </> 75 ) 76
Server
The heart of the backend application. Connects to the DB via
config/db and uses all routes made available by routes
and error handling directly from the
middleware.
Config/db
Makes the connection to the database.
Routes
Best regarded as Endpoints. Route methods (get, post, put, delete) are defined for the specified route and used in conjunction with a controller and middleware functions, which hold the logic. (e.g. router.post('/login', authUser))
Controllers
Best regarded as the application logic. The functions defined here will be requested when hitting the defined routes/endpoints. It is the place where the logic for a given route is applied.
Models
Defines the DB schema for a given model. also uses bcrypt to compare and hash passwords.